Way back in 2009, PHP 5.3 was released to the world and with it brought support for PHP namespaces — a way of easily separating your code from other developers’ code, which has since become the de facto way of encapsulating functionality across the PHP ecosystem.

With namespaces, multiple packages could use the same class and function names without conflict, because each one would operate in their own PHP namespaces:

<?php /** * Functionality for Package A. */ namespace SteveGrunwell\PackageA; function do_something() { // Do something } 1 2 3 4 5 6 7 8 9 10 <?php /** * Functionality for Package A. */ namespace SteveGrunwell \ PackageA ; function do_something ( ) { // Do something }

Since that code lives within the SteveGrunwell\PackageA namespace (as declared at the top of the file), I could use the code seamlessly next to:

<?php /** * Functionality for Package B. */ namespace SteveGrunwell\PackageB; function do_something() { // Do something totally different than Package A. } 1 2 3 4 5 6 7 8 9 10 <?php /** * Functionality for Package B. */ namespace SteveGrunwell \ PackageB ; function do_something ( ) { // Do something totally different than Package A. }

While both packages define a do_something() function, the functions from Package A and Package B exist in different PHP namespaces ( SteveGrunwell\PackageA and SteveGrunwell\PackageB , respectively).

What’s in a name(space)?

Conventionally, PHP namespaces will follow the pattern of {vendor}\{package} , such as SteveGrunwell\PackageA in the examples above. If you’re working as part of a development or product team, you might also consider nesting namespaces (for example, some things I’ll build as an engineer on the Managed WordPress (MWP) product at Liquid Web might live under the LiquidWeb\MWP\{package} PHP namespace.

Nesting namespaces can be a really useful feature, especially when you’re dealing with lots of similar functionality. For example, my Schemify plugin uses PHP namespaces (and autoloading, which is a topic all in itself). Here’s an excerpt from the Schemify\Schemas\CreativeWork class:

<?php /** * The CreativeWork Schema. * * @package Schemify * @link http://schema.org/CreativeWork */ namespace Schemify\Schemas; class CreativeWork extends Thing { // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 <?php /** * The CreativeWork Schema. * * @package Schemify * @link http://schema.org/CreativeWork */ namespace Schemify \ Schemas ; class CreativeWork extends Thing { // ... }

Since I wanted to separate the individual schema definitions from the rest of the plugin code, I put them in the Schemify\Schemas namespace (Schemify doesn’t currently use a vendor namespace, so the main plugin code is in Schemify instead of SteveGrunwell\Schemify ).

Working with functions defined in PHP namespaces

To call these functions from within the same namespace, we can simply reference the function by name; if I added a do_something_else() function within the SteveGrunwell\PackageA namespace, I can simply call do_something() and it’s implied that I’m referencing SteveGrunwell\PackageA\do_something() .

If we need to call functions in different namespaces, we can do it in a few different ways:

First, we can reference the function name prefixed with the full PHP namespace

<?php namespace SteveGrunwell\PackageB; function do_something() { // Call do_something() from Package A. $packageA = \SteveGrunwell\PackageA\do_something(); } 1 2 3 4 5 6 7 8 <?php namespace SteveGrunwell \ PackageB ; function do_something ( ) { // Call do_something() from Package A. $packageA = \ SteveGrunwell \ PackageA \ do_something ( ) ; }

That’s probably my least favorite way to use namespaces, but is perfectly valid (especially if you’re only referencing the function from Package A once or twice.

Next, we can import code from other PHP namespaces into the current namespace via the use keyword:

<?php namespace SteveGrunwell\PackageB; use SteveGrunwell\PackageA as A; function do_something() { // Call do_something() from Package A. $packageA = A\do_something(); } 1 2 3 4 5 6 7 8 9 10 <?php namespace SteveGrunwell \ PackageB ; use SteveGrunwell \ PackageA as A ; function do_something ( ) { // Call do_something() from Package A. $packageA = A \ do_something ( ) ; }

Finally, we can import the specific functions we need into the current namespace via use function (note: this is only available in PHP 5.6 or newer):

<?php namespace SteveGrunwell\PackageB; use function SteveGrunwell\PackageA\do_something as pkgA; function do_something() { // Call do_something() from Package A. $packageA = pkgA(); } 1 2 3 4 5 6 7 8 9 10 <?php namespace SteveGrunwell \ PackageB ; use function SteveGrunwell \ PackageA \ do_something as pkgA ; function do_something ( ) { // Call do_something() from Package A. $packageA = pkgA ( ) ; }

Each of these approaches is valid and has good use-cases, producing the same result.

Classes and PHP namespaces

Where PHP namespaces become really handy are when we’re dealing with object-oriented programming (OOP). Instead of dealing with importing specific functions, we can tell PHP “when I reference a given class name, I’m referring to this specific class.”

Let’s say I’m writing my own WP-CLI command, which I’ll put in the SteveGrunwell\MyCommand namespace:

<?php /** * My custom WP-CLI command. */ namespace SteveGrunwell\MyCommand; class Command extends WP_CLI_Command { // Define my custom command here. } 1 2 3 4 5 6 7 8 9 10 <?php /** * My custom WP-CLI command. */ namespace SteveGrunwell \ MyCommand ; class Command extends WP_CLI_Command { // Define my custom command here. }

If I were to try to load my command just like that, PHP would give me an error to the effect of “Class SteveGrunwell\MyCommand\WP_CLI_Command does not exist”, because the WP_CLI_Command class is defined in the global namespace (in other words, is not namespaced).

I can solve this by adding a single import to my file:

<?php /** * My custom WP-CLI command. */ namespace SteveGrunwell\MyCommand; use WP_CLI_Command; class Command extends WP_CLI_Command { // Define my custom command here. } 1 2 3 4 5 6 7 8 9 10 11 12 <?php /** * My custom WP-CLI command. */ namespace SteveGrunwell \ MyCommand ; use WP_CLI_Command ; class Command extends WP_CLI_Command { // Define my custom command here. }

With that use statement in place, PHP will now understand that SteveGrunwell\MyCommand\Command extends WP_CLI_Command , which lives in the global PHP namespace.

Using PHP namespaces in WordPress themes and plugins

Now that we have a basic understanding of what PHP namespaces are and how to use them, let’s take a look at namespaces from a WordPress perspective:

WordPress development through the ages

I’ve written a bit about this before, but in the early days of WordPress development, plugin developers might write a function that looks like this:

<?php function get_recent_posts( $limit = 5 ) { return new WP_Query( array( 'post_type' => 'post', 'post_status' => 'publish', 'orderby' => 'post_date', 'order' => 'desc', 'posts_per_page' => $limit, ) ); } 1 2 3 4 5 6 7 8 9 10 11 <?php function get_recent_posts ( $limit = 5 ) { return new WP_Query ( array ( 'post_type' = > 'post' , 'post_status' = > 'publish' , 'orderby' = > 'post_date' , 'order' = > 'desc' , 'posts_per_page' = > $limit , ) ) ; }

However, the developer might find that another theme or plugin — or even WordPress core itself — introduces a get_recent_posts() function, which then causes the site to break because PHP has received two separate declarations of a get_recent_posts() function.

To get around this, developers started prefixing their function names with their theme/plugin slug or another unique identifier; get_recent_posts() might become myplugin_get_recent_posts() . Suddenly, the chances of a name collision dropped, but function names would get longer and longer. Developers with multiple plugins might find themselves adding vendor names, resulting in functions like grunwell_myplugin_get_recent_posts() , which made the code harder to read.

Next, some enterprising developers thought “wait a second, why don’t we just encapsulate everything in classes?”, so we ended up with classes that looked something like this:

<?php class MyPlugin { public function get_recent_posts( $limit = 5 ) { return new WP_Query( /* ... */ ); } } 1 2 3 4 5 6 7 <?php class MyPlugin { public function get_recent_posts ( $limit = 5 ) { return new WP_Query ( /* ... */ ) ; } }

As a result, developers would need to instantiate (e.g. create an instance of) these classes, so we often ended up with messy global variable declarations:

global $my_plugin; $my_plugin = new MyPlugin(); 1 2 3 global $my_plugin ; $my_plugin = new MyPlugin ( ) ;

As an aside, this approach is contrary to the underlying concepts of object-oriented programming (wherein instances of objects interact with each other), but that’s beyond the scope of this post.

From here, developers seem to have split into two factions: the first, dead-set on removing global variables, moved toward the Singleton pattern:

# Class definition: class MyPlugin() { protected static $instance; protected function __construct() { // Made protected to prevent `new MyPlugin()` calls. } public static function get_instance() { if ( ! self::$instance ) { self::$instance = new MyPlugin(); } return self::$instance; } public function get_recent_posts( $limit = 5 ) { return new WP_Query( /* ... */ ); } } # Usage: $plugin = MyPlugin::get_instance(); $recent_posts = $plugin->get_recent_posts(); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # Class definition: class MyPlugin ( ) { protected static $instance ; protected function __construct ( ) { // Made protected to prevent `new MyPlugin()` calls. } public static function get_instance ( ) { if ( ! self : : $instance ) { self : : $instance = new MyPlugin ( ) ; } return self : : $instance ; } public function get_recent_posts ( $limit = 5 ) { return new WP_Query ( /* ... */ ) ; } } # Usage: $plugin = MyPlugin:: get_instance ( ) ; $recent_posts = $plugin - > get_recent_posts ( ) ;

Some plugins (such as WooCommerce) took it a step further, and hid some of the get_instance() ugliness in an easily-referenced function:

# Definition: function my_plugin() { return MyPlugin::get_instance(); } # Usage: $recent_posts = my_plugin()->get_recent_posts(); 1 2 3 4 5 6 7 # Definition: function my_plugin ( ) { return MyPlugin:: get_instance ( ) ; } # Usage: $recent_posts = my_plugin ( ) - > get_recent_posts ( ) ;

Unfortunately, the Singleton pattern makes testing a bit of a bear and doesn’t really eliminate globals (while the global keyword isn’t used, you’re still storing a single reference to an object in a globally-static class property.

The second group of developers recognized that these plugins were rarely being handled as true objects, instead being used as pseudo-namespaces — constructs to encapsulate code from global namespace collisions without using true PHP namespaces. However, since WordPress still (at the time of this writing) supports PHP 5.2 (which lacks PHP namespace support), developers trying to reach the broadest possible audience still needed a way to reasonably encapsulate their code without relying on (or having to learn, depending on who you ask) PHP namespaces. The result was a class full of static methods, acting as a more-responsible pseudo-namespace:

# Class definition: class MyPlugin { public static function get_recent_posts( $limit = 5 ) { return new WP_Query( /* ... */ ); } } # Usage: $recent_posts = MyPlugin::get_recent_posts(); 1 2 3 4 5 6 7 8 9 # Class definition: class MyPlugin { public static function get_recent_posts ( $limit = 5 ) { return new WP_Query ( /* ... */ ) ; } } # Usage: $recent_posts = MyPlugin:: get_recent_posts ( ) ;

The 10up Engineering Best Practices (disclosure: I’ve contributed to those documents) does a great job of outlining common cases for this approach. Since the methods are static, we’re not creating rogue objects or abusing globals, but we’re still throwing code that likely doesn’t need to be object-oriented into classes; it’s a “it’s an ugly hack, but it’s the least ugly of the ugly hacks” approach.

Proper PHP namespaces in WordPress themes and plugins

Now that we’re up-to-speed, let’s take a look at that original get_recent_posts() function and see how we can get it working with PHP namespaces:

<?php namespace SteveGrunwell\MyPlugin; use WP_Query; function get_recent_posts( $limit = 5 ) { return new WP_Query( array( 'post_type' => 'post', 'post_status' => 'publish', 'orderby' => 'post_date', 'order' => 'desc', 'posts_per_page' => $limit, ) ); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php namespace SteveGrunwell \ MyPlugin ; use WP_Query ; function get_recent_posts ( $limit = 5 ) { return new WP_Query ( array ( 'post_type' = > 'post' , 'post_status' = > 'publish' , 'orderby' = > 'post_date' , 'order' = > 'desc' , 'posts_per_page' = > $limit , ) ) ; }

Can you spot the differences between this function and our original example? If not, I’ll give you a hint: it’s literally two lines at the top of the file, starting with namespace and use .

By adding the namespace declaration to the top of the file (and importing the WP_Query class from the global namespace, since our function uses it), we’re able to write clean, well-encapsulated code.

PHP namespaces and the WordPress Plugin API

One of the challenges I see when developers run into when learning to use namespaces within WordPress is the WordPress Plugin API (e.g. actions and filters). When working with functions in the global namespace, hooking into an action might look like this:

add_action( 'some_action', 'my_callback_function' ); 1 add_action ( 'some_action' , 'my_callback_function' ) ;

Likewise, calling methods inside a class often look like one of the following:

# With the class instance. add_action( 'some_action', array( $instance, 'my_callback_function' ) ); # With a Singleton. add_action( 'some_action', array( MyPlugin::get_instance(), 'my_callback_function' ) ); # A Singleton with a helper function. add_action( 'some_action', array( my_plugin(), 'my_callback_function' ) ); # A public, static method add_action( 'some_action', 'MyPlugin::my_callback_function' ); 1 2 3 4 5 6 7 8 9 10 11 # With the class instance. add_action ( 'some_action' , array ( $instance , 'my_callback_function' ) ) ; # With a Singleton. add_action ( 'some_action' , array ( MyPlugin:: get_instance ( ) , 'my_callback_function' ) ) ; # A Singleton with a helper function. add_action ( 'some_action' , array ( my_plugin ( ) , 'my_callback_function' ) ) ; # A public, static method add_action ( 'some_action' , 'MyPlugin::my_callback_function' ) ;

Fortunately, hooking callbacks that live within PHP namespaces looks much more like the first example:

add_action( 'some_action', '\SteveGrunwell\MyPlugin\my_callback_function' ); 1 add_action ( 'some_action' , '\SteveGrunwell\MyPlugin\my_callback_function' ) ;

If you’re referencing a callback function in the same (or a child) namespace, you may also use the __NAMESPACE__ PHP magic constant:

add_action( 'some_action', __NAMESPACE__ . '\my_callback_function' ); 1 add_action ( 'some_action' , __NAMESPACE__ . '\my_callback_function' ) ;

When hooking into namespaced callbacks, remember the leading backslashes!

Dealing with users on PHP 5.2

It’s hard to definitively say that every WordPress plugin should be using PHP namespaces, but it’s really easy to make the case that the majority of them should. According to WordPress.org, less than 4% (3.1%, at the time of this writing) of WordPress installations are running on PHP 5.2, and there are well-supported efforts within the community to drop support for PHP 5.2. Put bluntly, there’s no reason to continue to support WordPress sites running PHP 5.2.

However, if you’re building a plugin or theme that might be installed by users running PHP 5.2, you might consider the following approach: make your main plugin file (e.g. my-plugin/my-plugin.php ) act as a bootstrap for the rest of the plugin, and include a check for older versions of PHP. The result might look something like this:

my-plugin/my-plugin.php <?php /** * Plugin Name: My Plugin * Plugin URI: https://wordpress.org/plugins/my-plugin/ * Description: An example plugin * Version: 1.0.0 * Author: Steve Grunwell * Author URI: https://stevegrunwell.com * License: MIT */ /** * Deactivate the plugin if the site cannot support it. */ function myplugin_deactivate() { deactivate_plugins( plugin_basename( __FILE__ ) ); } /** * Display a notice informing the user that the plugin was deactivated. */ function myplugin_show_deactivation_notice() { echo wp_kses_post( sprintf( '<div class="notice notice-error"><p>%s</p></div>', __( '"My Plugin" requires PHP 5.3 or newer.', 'my-plugin' ) ) ); } if ( ! version_compare( PHP_VERSION, '5.3.0', '>=' ) ) { add_action( 'admin_init', 'myplugin_deactivate' ); add_action( 'admin_notices', 'myplugin_show_deactivation_notice' ); // Return early to prevent loading the other includes. return; } // Load the rest of the plugin files, which use namespaces. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <?php /** * Plugin Name: My Plugin * Plugin URI: https://wordpress.org/plugins/my-plugin/ * Description: An example plugin * Version: 1.0.0 * Author: Steve Grunwell * Author URI: https://stevegrunwell.com * License: MIT */ /** * Deactivate the plugin if the site cannot support it. */ function myplugin_deactivate ( ) { deactivate_plugins ( plugin_basename ( __FILE__ ) ) ; } /** * Display a notice informing the user that the plugin was deactivated. */ function myplugin_show_deactivation_notice ( ) { echo wp_kses_post ( sprintf ( '<div class="notice notice-error"><p>%s</p></div>' , __ ( '"My Plugin" requires PHP 5.3 or newer.' , 'my-plugin' ) ) ) ; } if ( ! version_compare ( PHP_VERSION , '5.3.0' , '>=' ) ) { add_action ( 'admin_init' , 'myplugin_deactivate' ) ; add_action ( 'admin_notices' , 'myplugin_show_deactivation_notice' ) ; // Return early to prevent loading the other includes. return ; } // Load the rest of the plugin files, which use namespaces.

Conclusion

Hopefully this crash-course in PHP namespaces has helped to demystify the topic, especially for PHP developers who focus mainly on WordPress. A strong understanding of PHP namespaces will not only help you better structure and encapsulate your code, but will also make it much easier to understand other projects written using more modern PHP methodologies.