Want to learn object-oriented programmming? Get my free course

Organizing your files in an object-oriented WordPress plugin

So you’ve made the plunge to the world of PHP object-oriented programming. You want to use that knowledge to build a plugin or convert your plugin to using objects. That’s great!

We’re going to talk about one of the first hurdles you might face when trying to work with PHP objects. That’s organizing your files. It’s an important topic with no general consensus in the WordPress community.

So why is file organization important? Well, let’s look at the code samples on this site to give you an idea. In general, each code sample tends to have a couple of classes and/or interfaces. They’re also small and only cover one specific WordPress problem.

But once you start building a real plugin, you’ll have to solve a lot of problems. That means that you’ll end up with a lot more classes. It can leave you feeling frustrated and looking for answers to questions like:

  • What do you do with them?
  • How do you structure my files and folders to accommodate them?
  • How do you load all the files containing them?

These are all questions that you’ll get an answer to in this article. So let’s get to it!

The importance of having standards

Before we move ahead, let’s discuss standards. Here is a great quote from the WordPress core contributor handbook.

Coding standards help avoid common coding errors, improve the readability of code, and simplify modification. They ensure that files within the project appear as if they were created by a single person.

Following up on the quote, they also ensure that anyone can dive into the code with relative ease. Whether it’s you coming back to an old project or a new hire diving into it for the first time. You know what to expect because the standards make it easy to do so.

The handbook covers coding standards for PHP, JavaScript, CSS and HTML. That said, the PHP standards don’t cover classes besides how to name them. This isn’t enough if you want to build plugins and/or themes using object-oriented programming. There’s nothing that explains to the community how to organize their code if they want to do that.

What is the rest of the PHP community doing?

This article is a great opportunity to bring up some of the standards used by the rest of the PHP community. The PHP Framework Interoperability Group (“PHP-FIG” for short) is the entity in charge of those standards.

It’s a group composed of PHP project representatives. Their goal is to increase the level of collaboration between PHP projects. Together, they created a set of standards that most new PHP projects use.

The development of those standards is one of the reasons for PHP’s renaissance in the last few years. This shows you what can happen if you nurture strong community-wide standards. They can have a huge benefit on an ecosystem as a whole.

Bringing some of that magic to WordPress

The goal of this article isn’t to bring those standards into WordPress. It’s to start working on a foundation that might allow for an integration with them in the future.

That said, it can’t happen without taking into account the standards already in place. In that spirit, this article will make suggestions that take them into consideration.

Organize everything around your classes

Surprising no one, we’ll see how to organize your files and folders around your classes.

One class per file

This is the most important recommendation. You might be thinking, “Holy Moley, that’s going to be a lot of files!”. That’s true. The advantages still outweigh that inconvenience. This is especially true once you add an autoloader which you’ll see a bit later. Let’s talk about those advantages.

Files are easier to name

Naming things is hard! By limiting your files to one class, you make it easy to name that file. It’s the name of that specific class! That’s super easy to do.

Less confusion

You also don’t have to worry about where to put a class when there are many classes per file. This eliminates a potential source of confusion. That’s because each of us has a unique reason for putting a class in a specific file.

It’s an arbitrary decision and thus open to interpretation. Limiting ourselves to one class per file simplifies everything. Each class gets its own file. That’s it!

Keeps your file sizes under control

Smaller files make it easier to read and find what you are looking for. When you have many classes per file, it’s easy for your files balloon to an unreasonable size (I won’t give a number!). It’s a lot harder to that when you have one class in your file.

Folder and file naming

Here, the article will divert from the file naming conventions from the core handbook. The enforcement of these standards seems arbitrary even in core.

That said, if you want to follow the WordPress naming standards, that’s fine! Just disregard the naming recommendations.

Transforming your class names into a file path

The goal here is to be compatible with PSR-0 by PHP-FIG. PSR stands for “Proposed Standards Recommendation”. PSR-0 is the initial standard accepted by the group meant for use with an autoloader (up next!).

Here is how you convert your class name to a file path:

  1. Convert each `_` character in the class name to a directory separator.
  2. Add `.php` to the last part of the class name.

So, for example, you would find the class MyPlugin_Admin_Page at the location /path/to/plugin/MyPlugin/Admin/Page.php.

This keeps the file names shorter but increases the folder depth. This is a worthwhile tradeoff for larger plugins. For smaller plugins, you don’t have to do it if it bothers you.

Using an autoloader

Autoloading files is the magical glue that makes the previous recommendations work together. It’s one of the landmark features of PHP5.

How it works

Let’s say PHP needs a specific class, but it can’t find it. In normal circumstances, it would just throw an error and leave you hanging. Not anymore! Now, you can register an autoloader.

An autoloader is a fallback for PHP that will try to require the file that would contain the missing class. If PHP found the class after using the autoloaders, you prevent PHP from throwing an error. MAGIC!

How the autoloader finds that file is up to you. You could hard code it or use a convention (WordPress, PSR-0 or something else).

Some examples

We’re going to go over two autoloader examples. One that is compatible with PSR-0 and PHP 5.2. This means that it won’t cover namespaces which are only available in PHP 5.3. You’ll see a second one modified to work with the WordPress convention.

PSR-0 Example

Let’s take a look at a PSR-0 autoloader.

/**
 * Autoloads MyPlugin classes using PSR-0 standard.
 *
 * @author Carl Alexander
 */
class MyPlugin_Autoloader
{
    /**
     * Registers MyPlugin_Autoloader as an SPL autoloader.
     *
     * @param boolean $prepend
     */
    public static function register($prepend = false)
    {
        if (version_compare(phpversion(), '5.3.0', '>=')) {
            spl_autoload_register(array(new self, 'autoload'), true, $prepend);
        } else {
            spl_autoload_register(array(new self, 'autoload'));
        }
    }

    /**
     * Handles autoloading of MyPlugin classes.
     *
     * @param string $class
     */
    public static function autoload($class)
    {
        if (0 !== strpos($class, 'MyPlugin')) {
            return;
        }

        if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
            require_once $file;
        }
    }
}

There are two functions to our autoloader. The register method registers the autoloader with PHP. The only unusual thing about it is that you need to check for the PHP version. That’s because the function changed in PHP 5.3.

The autoload method converts a class name to a file path and requires it. First, it checks if our file starts with our plugin prefix which is MyPlugin. If it’s one of our plugin classes, it converts the class name to a PSR-0 file path.

WordPress convention example

Now, we’re going to make changes to the PSR-0 autoloader. We’re going to have it follow the WordPress convention instead of the PSR-0 one. We can do that by changing the line that converts the class name to a file path in the autoload method.

if (is_file($file = dirname(__FILE__).'/class-'.strtolower(str_replace(array('_', "\0"), array('-', ''), $class).'.php'))) {
    require_once $file;
}

Here’s the new class name conversion code. It now converts class names to file names that follow the WordPress conventions. Those are:

  • Prepend class file names with `class-`.
  • Lowercase class file names.
  • Convert `_` in class names to `-`.

Another important change is that it only checks in the same folder as the autoloader file. That’s because all class files should be in the same folder. You can find the resulting class below.

/**
 * Autoloads MyPlugin classes using WordPress convention.
 *
 * @author Carl Alexander
 */
class MyPlugin_Autoloader
{
    /**
     * Registers MyPlugin_Autoloader as an SPL autoloader.
     *
     * @param boolean $prepend
     */
    public static function register($prepend = false)
    {
        if (version_compare(phpversion(), '5.3.0', '>=')) {
            spl_autoload_register(array(new self, 'autoload'), true, $prepend);
        } else {
            spl_autoload_register(array(new self, 'autoload'));
        }
    }

    /**
     * Handles autoloading of MyPlugin classes.
     *
     * @param string $class
     */
    public static function autoload($class)
    {
        if (0 !== strpos($class, 'MyPlugin')) {
            return;
        }

        if (is_file($file = dirname(__FILE__).'/class-'.strtolower(str_replace(array('_', "\0"), array('-', ''), $class).'.php'))) {
            require_once $file;
        }
    }
}

This is a good alternative for anyone that wants to be closer to the WordPress convention. You also don’t have to deal with the increased folder depth that PSR-0 brings.

Registering the autoloader

Registering the autoloader is painless. You need to require the autoloader class file and then call the register method.

Here is how the PSR-0 autoloader would behave:

require_once __DIR__ . '/MyPlugin/Autoloader.php';
MyPlugin_Autoloader::register();

// Found at /MyPlugin/Plugin.php
$plugin = new MyPlugin_Plugin();

Meanwhile, a WordPress convention autoloader would behave like:

require_once __DIR__ . '/_inc/class-myplugin-autoloader.php';
MyPlugin_Autoloader::register();

// Found at /_inc/class-myplugin-plugin.php
$plugin = new MyPlugin_Plugin();

You could also leave the autoloader in the root of your plugin.

What about other types of files

This is a situation where having some community-wide standards would help. That’s because there’s no right answer here. Here are some possible ways to you could handle it:

  • Separate directories (/css, /js, etc.) in the root of the plugin
  • Separate directories, but not in the root (/assets/css, /assets/js, etc.)
  • Combination of both (/assets/css, /assets/js, /languages, etc.)

You just have to pick one and stick with it. The main point is that a community-wide standard would help with that problem.

It’s about establishing a standard for using objects

This all goes back to the need for standards. It’s not easy to learn about object-oriented programming. WordPress doesn’t do the best it could to help you either.

That’s why writing about these standards is so important. It makes figuring things out easier for you and the others that will come after you.

Creative Commons License