Implementing namespaces in plugin template
-
07-01-2021 - |
Question
To get with the time and improve my coding practices, I'm starting to implementing namespaces in my own plugins moving forward since there are some advantages, such as eliminating ambiguity.
I found a similar question to help me set up my plugin template which worked for me. However, I've since modified it slightly. This is my setup:
In wp-plugin-template/wp-plugin-template.php
:
<?php
/**
* Plugin Name: WP Plugin Template
*/
# If accessed directly, exit
if ( ! defined( 'ABSPATH' ) ) exit;
# Call the autoloader
require_once( 'autoloader.php' );
use PluginTemplate\admin\Plugin_Meta;
new Plugin_Meta;
In wp-plugin-template/autoloader.php
:
<?php
spl_autoload_register( 'autoload_function' );
function autoload_function( $classname ) {
$class = str_replace( '\\', DIRECTORY_SEPARATOR, str_replace( '_', '-', strtolower($classname) ) );
# Create the actual file-path
$path = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $class . '.php';
# Check if the file exists
if ( file_exists( $path ) ) {
# Require once on the file
require_once $path;
}
}
In wp-plugin-template/admin/plugin-meta.php
:
<?php
namespace PluginTemplate\admin;
class Plugin_Meta {
public function __construct() {
add_action( 'plugins_loaded', array($this, 'test' ) );
}
public function test() {
echo 'It works!';
}
}
When I try to activate the plugin template for testing, I get the following error:
Fatal error: Class
PluginTemplate\admin\Plugin_Meta
not found inwp-content/plugins/wp-plugin-template/wp-plugin-template.php
on line 11
In this case, line 11 is:
new Plugin_Meta;
I think this is due to me having the namespace named PluginTemplate
? What am I doing wrong? Just to reiterate, the previous question that I mentioned worked for me before I started to rename my files and directories.
Solution
The problem is with your Autoloader set-up. You need to convert your Camelcase namespacese to dashes for locating files as per your current folder structure.
I have added convert function and updated your autoloader function.
In wp-plugin-template/autoloader.php
:
<?php
spl_autoload_register( 'autoload_function' );
function autoload_function( $classname ) {
$class = str_replace( '\\', DIRECTORY_SEPARATOR, str_replace( '_', '-', strtolower(convert($classname)) ) );
# Create the actual file-path
$path = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . $class . '.php';
# Check if the file exists
if ( file_exists( $path ) ) {
# Require once on the file
require_once $path;
}
}
function convert($class){
$class = preg_replace('#([A-Z\d]+)([A-Z][a-z])#','\1_\2', $class);
$class = preg_replace('#([a-z\d])([A-Z])#', '\1_\2', $class);
return $class;
}
Also you have to update your top level namespace to WpPluginTemplate
in both wp-plugin-template.php
and admin/plugin-meta.php
as you are using wp-plugin-template as your plugin folder name.
UPDATE:
When autoloader tries to find Plugin_Meta
class, it will look into YOUR_PLUGIN_DIR/wp-plugin-template/admin/plugin-meta.php
In wp-plugin-template.php
<?php
/**
* Plugin Name: WP Plugin Template
*/
# If accessed directly, exit
if ( ! defined( 'ABSPATH' ) ) exit;
# Call the autoloader
require_once( 'autoloader.php' );
use WpPluginTemplate\admin\Plugin_Meta;
new Plugin_Meta;
In wp-plugin-template/admin/plugin-meta.php
<?php
namespace WpPluginTemplate\admin;
class Plugin_Meta {
public function __construct() {
add_action( 'plugins_loaded', array($this, 'test' ) );
}
public function test() {
echo 'It works!';
}
}
OTHER TIPS
Just some additional note about your autoloader:
If the $classname
input is PluginTemplate\admin\Plugin_Meta
then the $path
becomes
/full/path/to/wp-content/plugins/plugintemplate/admin/plugin-meta.php
and this file doesn't exists and the Plugin_Meta
class definition isn't loaded.
It's also not recommended to use the WP_PLUGIN_DIR
constant directly, there are alternatives, like plugin_dir_path( __FILE__ )
.
There are more complete autoloaders out there, e.g. the generated autoloader in Composer.