16 02 2012
How I write my WordPress Plugins with Classes
One of the things I’ve always hated about WordPress is writing larger plugins with lots of functions and global variables. While it isn’t always possible to write a wordpress plugin using OOP techniques that would satisfy an OOP purist, it is possible to make things a little cleaner and easier to extend and maintain for yourself.
Update: This way of using classes is not a pure OO way of designing a plugin, it’s mainly a way of namespacing your code and keeping as much as possible out of the global namespace. I’ll write a post in future detailing some of the concepts I now use for writing plugins such as using php 5.3 namespaces and using real OO design in my plugins.
The following tutorial is for php 5+ and outlines a basic structure for an object orientated wordpress plugin. You could take these examples as far as you want, however at some point you will have to decide between speed, flexibility and design.
I say this because I believe you can reach a happy medium between writing wordpress plugins and using classes. Sure it will not strictly adhere to standards that you may be used to using but you will have to directly call core wordpress core functions eventually.
I choose not to introduce extra layers of functionality by wrapping core wordpress variables like wpdb and instead use them in my class methods by a global variable. This is not pretty and not to standards, but I choose this over wrapping all of the wordpress core and slowing down my applications, also this is the wordpress way.
If you have suggestions or improvements, please leave a comment. Without further ado, here is a basic shell wrapper for a plugin. (zip file at end of article).
my-plugin/my-plugin.php
This is the main WP plugin file. It chooses which main class (admin or public) to initialize by checking the wordpress function is_admin. This allows us to keep admin plugin code and code that runs on the public site separate.
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 |
/* Plugin Name: My Plugin Description: How to design a plugin with classes Version: 1.0 Author: Greg F Author URI: http://www.gregfreeman.io */ define( 'MY_PLUGIN_PATH', dirname( __FILE__ ) ); define( 'MY_PLUGIN_URL', plugins_url( '', __FILE__ ) ); define( 'MY_PLUGIN_FILE', plugin_basename( __FILE__ ) ); define( 'MY_PLUGIN_INC', MY_PLUGIN_PATH . '/inc' ); require_once( MY_PLUGIN_INC . '/plugin.php' ); require_once( MY_PLUGIN_INC . '/config.php' ); $my_class = 'My_'; if ( is_admin() ) { $my_class .= 'Admin'; require_once( MY_PLUGIN_INC . '/admin.php' ); } else { $my_class .= 'Public'; require_once( MY_PLUGIN_INC . '/theme-functions.php' ); require_once( MY_PLUGIN_INC . '/public.php' ); } $my_config_data = array( 'plugin_file' => MY_PLUGIN_FILE, ); $my_plugin = new $my_class( new My_Config( $my_config_data ) ); unset( $my_class, $my_config_data ); |
my-plugin/inc/plugin.php
This is the base class that admin and public extend. It makes the config class available to both subclasses and has two methods for plugging into WP filters and actions. It also calls an init function that is used by admin and public to setup filters and actions.
All of your filter/action calls should go into the init method in My_Admin or My_Class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
abstract class My_Plugin { protected $_config; public function __construct( My_Config $config ) { $this->_config = $config; $this->init(); } abstract protected function init(); protected function add_action( $action, $function = '', $priority = 10, $accepted_args = 1 ) { add_action( $action, array($this, $function == '' ? $action : $function ), $priority, $accepted_args ); } protected function add_filter( $filter, $function, $priority = 10, $accepted_args = 1 ) { add_filter( $filter, array($this, $function == '' ? $filter : $function ), $priority, $accepted_args ); } } |
my-plugin/inc/config.php
This is a basic wrapper for config variables, in this example it stores things like the base plugin path and file. In your plugin it could wrap wordpress options and calls to get_option.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class My_Config { protected $config; public function __construct( array $config ) { $this->config = $config; } public function __get( $name ) { $value = false; if ( array_key_exists( $name, $this->config ) ) { $value = $this->config[$name]; } return $value; } } |
my-plugin/inc/admin.php
Here is the admin class. In this example it registers the activation hook. See the public class below for more ways to use this setup.
In My_Admin you will normally have filter/action calls to admin_init, save_post, add_meta_boxes etc. You can use the wordpress settings_api inside of your admin_init method.
1 2 3 4 5 6 7 8 9 |
class My_Admin extends My_Plugin { protected function init() { register_activation_hook( $this->_config->plugin_file, array( $this, 'activate' ) ); } public function activate() { // plugin activate code } } |
my-plugin/inc/public.php
The public class has everything that is needed for the frontend site. In this example (commented out) It adds a filter for pre_get_posts which adds a custom post type to all queries on the frontend. A second function called say_hello is created to perform a basic greeting.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class My_Public extends My_Plugin { protected function init() { //$this->add_filter( 'pre_get_posts', 'set_post_types' ); } public function set_post_types( $query ) { $query->set( 'post_type', array( 'post', 'my_custom_post_type' ) ); return $query; } public function say_hello( $name = '' ) { $greeting = 'hello'; if( $name ) { $greeting .= ' ' . esc_attr( $name ); } echo $greeting; } } |
my-plugin/inc/theme-functions.php
Theme functions holds all of the functions that are called on templates. Instead of calling $my_plugin->say_hello( ‘greg’ ); ?> in your theme, you can type my_say_hello( ‘greg’ ); instead. This is optional and is only included to avoid typing additional characters that may be unfamiliar to designers etc.
1 2 3 4 |
function my_say_hello( $name = '' ) { global $my_plugin; $my_plugin->say_hello( $name ); } |
I hope this helps you with your wordpress plugin classes! Using this setup, your plugin only creates one global variable called $my_plugin in the my-plugin/my-plugin.php file. The other major advantages is the ability to ‘hide’ code using protected/private variables and methods. This allows you to stop normal wordpress users from calling internal functions and restricts them only to your public facing ‘API’.
Let me know if you have suggestions.
Remove Icon from Application Title in Gnome 3 Recovery from cinnamon crashes and freezes in Linux Mint
Looks like a pretty airtight way to ensure your functions are not accidentally triggered or clashing. Definitely got a lot of improvements to make in how I’ve been structuring functions and whatnot.
Very lovely tips. Thanks for sharing!
Can you please suggest me a book which provides wordpress plugin development using classes in object oriented way.