DEV Community

Cover image for Namespaces in WordPress plugin development
Marcus Kober
Marcus Kober

Posted on • Originally published at marcuskober.com

Namespaces in WordPress plugin development

In this article I'll point out, what's the reason for using namespaces in our WordPress plugins and what namespaces are. We will learn, that namespaces are important for the upcoming topics in this series.

The problem with naming constants, functions, and classes in WordPress plugins

Avoiding name collisions is of paramount importance in plugin development. If you use constants, functions, and classes directly in your plugin file, these are registered in the global namespace. Therefore, there is a risk that you will overwrite constants, functions, or classes from other plugins (or from WordPress itself), or vice versa. As a result, your plugin (or other plugins) may not function correctly, or a PHP error may be thrown.

So, let’s assume that there are two plugins installed on our system, each declaring a function called plugin_init():

Plugin file plugin-01/plugin-01.php:

<?php
/*
 * Plugin Name: Plugin #1
 */

function plugin_init() {
    // some code
}
Enter fullscreen mode Exit fullscreen mode

Plugin file plugin-02/plugin-02.php:

<?php
/*
 * Plugin Name: Plugin #2
 */

function plugin_init() {
    // some code
}
Enter fullscreen mode Exit fullscreen mode

This will lead to the following error: PHP Fatal error: Cannot redeclare plugin_init() (previously declared in /../plugin-01/plugin-01.php). The reason behind this is that PHP does not allow the declaration of two functions with the same name.

Using a prefix to solve this problem

We can now come up with a prefix for our plugin, which we will then use consistently throughout our plugin. A prefix is just a string of characters that we put in front of our function and class names, usually followed by an underscore.

Please keep in mind that the prefix must be as unique as possible. If we only use our plugin name, it is possible that another plugin also has that name, which then leads to naming conflicts again. A short combination of your name and the name of your plugin should generally be safe.

Example:

<?php
/*
 * Plugin Name: Prefixed plugin
 */

function mk_pp_plugin_init() {
    // some code
}

function mk_pp_get_data() {
    // some code
}

// ...
Enter fullscreen mode Exit fullscreen mode

In this example, we have chosen mk_pp as a prefix (a short form of Marcus Kober and an abbreviation for the plugin) and now use this for all our constants and functions. As you can see, this leads to long names and surely doesn’t contribute to clarity and readability. However, such a prefix is relatively safe. But can’t we do it even more elegantly?

What are namespaces?

Namespaces offer the ability to encapsulate elements of your code so as not to cause name collisions. Essentially, namespaces are a mechanism for organizing functions, classes, and constants. A namespace defines a unique area in which the names of functions and classes are encapsulated. This makes it possible to use identical names within different namespaces.

You can also imagine namespaces like a folder system. The “subfolders” are separated with backslashes (/).

For the root namespace, I recommend using your name or that of your company, or an abbreviation thereof. In my case, that would be MK. Then follows the name of your plugin (or an abbreviation thereof): MK\MyPlugin.

We use namespaces

The namespace is defined at the beginning of each PHP file in your plugin. Of course, you should again make sure not to use too generic namespaces like simply Plugin, as this could also lead to a name collision of the namespace.

Example:

<?php
/*
 * Plugin Name: Namespaced plugin
 */

namespace MK\NamespacePlugin;

function plugin_init() {
    // some code
}

function get_data() {
    // some code
}

// ...
Enter fullscreen mode Exit fullscreen mode

The fully qualified name of the function plugin_init() is now: MK\NamespacePlugin\plugin_init(). This resolves the potential name conflict with a possibly existing function plugin_init() in another plugin.

Namespaces in WordPress plugins

Now let’s try to register a function inside a namespace as a callback for a hook:

<?php
/*
 * Plugin Name: Namespaced plugin
 */

namespace MK\NamespacePlugin;

function plugin_init() {
    // some code
}

add_action('init', 'plugin_init');
Enter fullscreen mode Exit fullscreen mode

This will lead to a Fatal error:

Fatal error: Uncaught TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback, function "plugin_init" not found or invalid function name
Enter fullscreen mode Exit fullscreen mode

Why does this error message appear? After all, the function plugin_init() does exist in our plugin. To understand, let’s look at the file where the error occurs. In the PHP error description, we see below:

thrown in /.../wp-includes/class-wp-hook.php on line 308
Enter fullscreen mode Exit fullscreen mode

So, the error occurs in the WordPress core file class-wp-hook.php, where the core function apply_filters() is defined, which calls the callback that we defined in add_action(). However, the file class-wp-hook.php is outside of the namespace MK\NamespacePlugin that we defined, which is why we need to give the function add_action() the fully qualified name of the function:

<?php
/*
 * Plugin Name: Namespaced plugin
 */

namespace MK\NamespacePlugin;

function plugin_init() {
    // some code
}

add_action('init', 'MK\NamespacePlugin\plugin_init');
Enter fullscreen mode Exit fullscreen mode

So that we don’t have to manually type in the full name everywhere, we can also provide the call with the magic constant __NAMESPACE__, which contains the name of the current namespace as a string:

add_action('init', __NAMESPACE__ . 'plugin_init');
Enter fullscreen mode Exit fullscreen mode

Conclusion

Using namespaces is a clean and efficient way to encapsulate our constants, functions, and classes from the global namespace and thus prevent name collisions.

In the next article of this series, we will also see that we need namespaces for autoloading and the folder structure of plugins.

Top comments (0)