Gutenberg Sidebar – Setting up the Autoloader

Gutenberg Sidebar - Setting up the Autoloader

Setting up an autoloader in PHP and for your WordPress plugin is a fairly easy process. When you see the end result, you’ll no doubt be underwhelmed. However, this begs the question… what are autoloaders, why are they useful, and what do they offer?

The Concept of Autoloading

To begin, let’s first explore what autoloaders actually are.

What are Autoloaders?

Autoloading has been around a while, especially if you come from the land of Composer. Instead of having a bunch of requires and includes, you can simply access, use, or instantiate any class at any moment.

Say for example we have a plugin structured like the following:

. └── my-cool-plugin ├── my-cool-plugin.php └── includes ├── class-functions.php ├── class-options.php └── class-admin.php
Code language: AsciiDoc (asciidoc)

If you wanted to include something from admin, you’d first have to include the file and then instantiate the class based on assumptions the class loaded in just fine. This works for most, but an autoloader just saves you so much sanity.

For example, in my-cool-plugin.php we want to include the admin, but we’ll also need access to all the functions and options.

So in my-cool-plugin.php, you’d do:

require 'includes/class-admin.php'; require 'includes/class-functions.php'; require 'includes/class-options.php';
Code language: PHP (php)

In the main plugin file, we need all of them for some random reason, but the admin also needs the class-options.php and class-functions.php. So in Admin, you’d have to somehow be instantiated and that’ll run the necessary requires either at the top of the file or conditionally via require_once.

With autoloading and namespaces (let’s assume a namespace of WPAJAX), we can just do the following:

new WPAJAX\Includes\Admin();
Code language: PHP (php)

This will automatically instantiate the class-admin.php object. You can even assign the class instance to a global available object in the main plugin file or some kind of loading file.

$this->admin = new \WPAJAX\Includes\Admin();
Code language: PHP (php)

And then inside admin, there’s no need to know the exact path of the functions or options file.

namespace WPAJAX\Includes; use WPAJAX\Includes\Options as Options; class Admin { }
Code language: PHP (php)

The benefit of an autoloader and PHP namespaces is that you can set your PHP paths a bit more strict and put a bit more thought into how your plugin is laid out.

Why Autoloaders and Namespaces Are Useful

Autoloaders and Namespaces are useful because they follow a predictable structure which is essentially mapped to a well-architected folder structure. For example, place all of the admin-related functionality in a /includes/admin/ folder.

. └── my-cool-plugin ├── my-cool-plugin.php └── includes └── admin ├── class-get-options.php ├── class-set-options.php ├── class-register-settings.php ├── class-output-settings.php └── class-enqueue-scripts.php
Code language: AsciiDoc (asciidoc)

It follows a semi-predictable structure, so you can access class-get-options.php by simply doing:

$options = new \WPAJAX\Includes\Admin\Get_Options(); $defaults = $options->get_defaults();
Code language: PHP (php)

A good autoloader will just grab the file based on the namespace path you provide it.

Furthermore, it prevents the need for global options. Other plugins such as add-ons can use your namespaces to retrieve files it shares functionality with such as hook, filters, or just needing access to a static method.

What do Autoloaders Offer?

It’s simply a predictable way in your code where you can access various classes in a predictable and repetitive manner and to only load in other classes or pieces of code as needed instead of a ton of requires and includes near the beginning of plugin execution to access classes.

No more need to set global variables or have always in-scope functions so others can access a piece of code you’d like them to render from another project.

Anyways, let’s move on to setting up an autoloader in our landing page Gutenberg sidebar project.

Setting Up the Autoloader

I have to be honest, I stole this autoloader from an open-source project called Block Lab because I thought it was so genius. I have since used it on most every new project I have started and absolutely love it.

Here it is in all its glory:

<?php /** * Plugin Autoloader * * @package wpajax-landing */ /** * Register Autoloader */ spl_autoload_register( function ( $class ) { // Assume we're using namespaces (because that's how the plugin is structured). $namespace = explode( '\\', $class ); $root = array_shift( $namespace ); // If a class ends with "Trait" then prefix the filename with 'trait-', else use 'class-'. $class_trait = preg_match( '/Trait$/', $class ) ? 'trait-' : 'class-'; // If we're not in the plugin's namespace then just return. if ( 'WPAndAjax' !== $root ) { return; } // Class name is the last part of the FQN. $class_name = array_pop( $namespace ); // Remove "Trait" from the class name. if ( 'trait-' === $class_trait ) { $class_name = str_replace( 'Trait', '', $class_name ); } $filename = $class_trait . $class_name . '.php'; // For file naming, the namespace is everything but the class name and the root namespace. $namespace = trim( implode( DIRECTORY_SEPARATOR, $namespace ) ); // Because WordPress file naming conventions are odd. $filename = strtolower( str_replace( '_', '-', $filename ) ); $namespace = strtolower( str_replace( '_', '-', $namespace ) ); // Get the path to our files. $directory = dirname( __FILE__ ); if ( ! empty( $namespace ) ) { $directory .= DIRECTORY_SEPARATOR . $namespace; } $file = $directory . DIRECTORY_SEPARATOR . $filename; if ( file_exists( $file ) ) { require_once $file; } } );
Code language: PHP (php)

It’s simple, but it does quite a lot.

It first checks that the namespace begins with WPAndAjax, and if not, the autoloader can care less and exits.

// Assume we're using namespaces (because that's how the plugin is structured). $namespace = explode( '\\', $class ); $root = array_shift( $namespace ); // If a class ends with "Trait" then prefix the filename with 'trait-', else use 'class-'. $class_trait = preg_match( '/Trait$/', $class ) ? 'trait-' : 'class-'; // If we're not in the plugin's namespace then just return. if ( 'WPAndAjax' !== $root ) { return; }
Code language: PHP (php)

In the above code, we get the root namespace. If it’s WPAndAjax, we know we’re in business. Otherwise, the code returns and lets some other autoloader have a crack at it.

The rest of the code assumes a namespace file structure as explained above in the admin example. Once the final class name has been determined, it tries to check if it exists. If not, it will exit and let everything execute as normal.

if ( ! empty( $namespace ) ) { $directory .= DIRECTORY_SEPARATOR . $namespace; } $file = $directory . DIRECTORY_SEPARATOR . $filename; if ( file_exists( $file ) ) { require_once $file; }
Code language: PHP (php)

Of note is that it only requires one instance of the file. So no matter how many times you call the class via namespace, you ensure that it’s loaded and that it’s not loaded over and over again across your files.

The function used is PHP function called spl_autoload_register.

What this PHP function does is once called, it tells PHP to put the loader in a queue and call it when a new class is referenced or instantiated.

In a way, it’s us raising a sign that we’re on the lookout for some stuff to load and want to wait our turn.

The Main Plugin File

In the main plugin file, we just include the autoloader near the top of the file.

// Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } define( 'WPAJAX_LANDING_VERSION', '1.0.0' ); define( 'WPAJAX_LANDING_DIR', plugin_dir_path( __FILE__ ) ); define( 'WPAJAX_LANDING_URL', plugins_url( '/', __FILE__ ) ); define( 'WPAJAX_LANDING_SLUG', plugin_basename( __FILE__ ) ); define( 'WPAJAX_LANDING_FILE', __FILE__ ); define( 'WPAJAX_LANDING_PLUGIN_URI', 'https://github.com/wpajax/landing-page-gutenberg-template' ); // Setup the plugin auto loader. require_once 'autoloader.php';
Code language: PHP (php)

Conclusion

And that’s it for our autoloader. It’ll come in handy as we move onto more of the plugin functionality.