As some of your know, I have been developing WordPress utilities for a long time. Mostly for specific use cases that need some custom implementation. As a result of my long-term affiliation with the system, I am a firm believer in not modifying the core, thus my work involves creating plugins to augment normal functionality.
Over the years I have found that on certain big projects a normal plugin is just not enough. There have been times where I needed to borrow functionality from another plugin already implemented and performing some crazy require(../../other-plugin-file) sort of method always makes me cringe. I had already inherited a system where some developer created a common library that they then used require() statement to pull classes and functions into their plugins but even this seemed rather contrary to good design. I didn’t see the benefit of this cross pollination of plugin code and always felt that there has to be a better way.
Why can’t have code that is readily available like the WordPress Core itself?
This thought haunted me for some time before I stumbled upon a way I could build this library of code. I wanted it to be served from a central point rather than stuffed into a single bloated plugin that some in inadvertent user could then turn off. I formulated a theory of how the old multi-user plugins in the WordPress Network edition were designed. I began experimenting because I was unsure of whether or not the mu-plugins directory would be search when WP_ALLOW_MULTISITE was set to false. As it turns out with the release of WP3.0 the mu-plugins directory was integrated into the core along with all of the other multi-site functionality. In fact it’s mnemonic was changed to must-use so care must be given to your mu-plugins design. The important thing to remember about mu-plugins is that these plugins are automatically activated by the system. There is NO way, short of complete removal, to turn them off. That is precisely what makes this perfect for our CORE library code.
Let’s take a deeper look at something simple like admin messages. I wrote this class because I found myself reimplementing the same type admin messages in various plugins over and over again. Although it is not a very complicated system I got tired of the copy & paste dance to add the functionality to each new plugin. In addition if I decided to expand the functionality then I would then have to manually propagate these changes throughout the site. This is actually where I got the idea for creating my own CORE.
<?php /* Plugin Name: Admin Messages Version: 1.0 Description: Adds a convenient standardized class for rendering messages in the WordPress Admin console. BY itself the plugin does nothing more than make the class available to use. You must instantiate the Admin_Message in order to utilize it. Author: Mikel King Author URI: http://mikelking.com Plugin URI: http://olivent.com/wordpress-plugins/konexus-admin_messages */ // see: http://codex.wordpress.org/Plugin_API/Action_Reference/admin_notices class Admin_Message { const ERROR_DIV_CLASS_FMT = '<div id="message"><p><strong>%s</strong></p></div>'; const NORMAL_DIV_CLASS_FMT = '<div id="message"><p><strong>%s</strong></p></div>'; private $admin_msg; public $error_level; function __construct($message) { if (isset($message)) { $this->admin_msg = $message; } } public function get_admin_error_message() { if ($this->admin_msg) { $the_message = sprintf(self::ERROR_DIV_CLASS_FMT, $this->admin_msg); return($the_message); } } public function get_admin_normal_message() { if ($this->admin_msg) { $the_message = sprintf(self::NORMAL_DIV_CLASS_FMT, $this->admin_msg); return($the_message); } } public function set_admin_message_level($level) { if (isset($level)) { $this->error_level = $level; } else { $this->error_level = 'normal'; } } public function get_the_admin_message() { if ( $this->error_level == 'error') { return($this->get_admin_error_message()); } else { return($this->get_admin_normal_message()); } } public function show_the_admin_message() { print($this->get_the_admin_message()); } }
At this point with the file safely saved in my mu-plugins directory I can instantiate the class and set the appropriate message level then display the message when needed. Obviously performing an instantiation would only work if you were guaranteed that the class in question would always be available when you needed. Fortunately the mu-plugins facility built into WordPress makes this Core ‘like’ feature happen without a huge amount of technical debt.
I decided to create a test plugin to demonstrate how to utilize the library. While researching some tangential subjects I stumbled across this OOP tutorial that advocated building a central library in mu-plugins. I highly encourage you to review that content as well. It’s insight lead me to augment my implementation to utiized the author’s BasePlugin Class as shown below.
In the code sample below I have built a new class on the back of the two classes activated by WordPress’s mu-plugins facility. Notice that I did not have to require any of the supporting class code into the plugin. I simply used what is there and performed my actions as needed.
<?php /* Plugin Name: Test of CORE Admin Messages Class Version: 1.0 Description: Just testing... ;-P Author: Mikel King Author URI: http://mikelking.com Plugin URI: http://olivent.com/wordpress-plugins/konexus-admin_messages */ class Admin_Message_Test extends BasePlugin { protected static $initialized = false; public $notifier; public function __construct() { } public static function init(){ if (function_exists("is_admin") && is_admin() && function_exists('add_filter') && ! self::$initialized) { self::$initialized = true; } } public function check_state() { include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); if (is_plugin_active('admin-message-test/AdminMessageTest.php')) { $this->notifier = new Admin_Message('Admin Test message activated.'); add_action( 'admin_notices', array($this->notifier, 'show_the_admin_message' )); } } } $amt = Admin_Message_Test::get_instance(); $amt->check_state();
While I did add some safety net wrapping code for this example I would normally remove that in production as I am relying on the assumption that WordPress will make these things available to me without hesitation.
One disturbing issue that came up was the necessity to include_once( ABSPATH . ‘wp-admin/includes/plugin.php’ ); in this code. Normally the is_plugin_active() call should be provided by default in the WordPress admin area. The necessity of this call was strictly for the demonstration the admin message system as well as the use of a central CORE library.
Leave a Reply