Namespaces and Objects

Markdown editing for WordPress.

Parsedown Party is a new WordPress Plugin I wrote with PHP namespaces, Composer support, 90% code coverage, and Travis-CI for automatic testing and releases.

While writing this Plugin, I settled on some WordPress coding conventions that I’d like to talk about.

Namespaces

One of the weirder things I read as a WordPress Plugin developer are tips such as “prefix all your function with name_” or “put all your functions in a class and declare them as static.” This advice is to prevent code collisions with the other 53,123+ Plugins available for WordPress. Big number.

On the other hand, Packagist lists 164,796+ PHP Composer packages, does not follow the aforementioned recommendations and has no such code collisions. Why? Because they use namespaces.

PHP Namespaces have been available since 2009. Other programming languages such as Java or Perl have had them for longer. WordPress Core doesn’t encourage PHP Namespaces but the syntax is fully supported.

If my class is a bunch of static methods and nothing else then I am doing it wrong. I should instead write a library of functions. If I’m afraid of function name collisions then I should use Namespaces because they solve that exact problem and they work fine with WordPress.

add_action( 'login_head', '\Kizu514\Coolname\this_works_fine' );
add_filter( 'login_headerurl', '\Kizu514\Coolname\welcome_to_php' );

Objects

Another odd thing I see while browsing OPP (other people’s plugins) are objects with “mostly” static methods.  There is some object-oriented approach to the design but most of the methods are static because they hook into actions and filters.

I think that an object in a WordPress Plugin should have, at most, two static methods. Every other method in a class should be public, protected or private.

There are very few cases where static methods are necessary. Most of the time public methods can be used. At worst, namespaced functions can invoke objects as needed and these concerns should be separate.

Here’s an example of what I mean (the code must also have PHPDoc comments and properly declared fields but for brevity, I have omitted these):

namespace Kizu514\CoolClass;

class Plugin {
	static public function init() {
		if ( is_null( self::$instance ) ) {
			$obj1 = new \Obj1();
			$obj2 = new \Obj2();
			$obj3 = new \Obj4( new \Obj3() );
			self::$instance = new self( $obj1, $obj2, $obj3 );
			self::hooks( self::$instance );
		}
		return self::$instance;
	}

	static public function hooks( Plugin $obj ) {
		add_action( 'save_post', [ $obj, 'doSomething' ] );
		add_filter( 'the_content', [ $obj, 'doSomethingElse' ] );
	}

	public function __construct( $obj1, $obj2, $obj3 ) {
		$this->obj1 = $obj1;
		$this->obj2 = $obj2;
		$this->obj3 = $obj3;
	}

	public function doSomething( $post_id ) { /**/ }

	public function doSomethingElse( $content) { /**/ }
}

Some time passes….

add_action( 'after_setup_theme', [ '\Kizu514\CoolClass\Plugin', 'init' ] );

The first static method, init, is hooked into one of many available launch points like plugins_loadedafter_setup_theme, or init. Because these actions happen before everything else a second static method, hooks, can do the rest of the work from inside the object itself.

Admittedly, even if I am down to just two static methods, they are gross. Glaring problems include “Singletons are evil” and not using Inversion of Control.

I’m very happy with this code style and I will be using it moving forward.

Leave a Reply

Your email address will not be published. Required fields are marked *