Posted by on in iDevelop, PHP | 1 comment

At BarCamp Delhi 9 someone asked me how I go about developing on WordPress and what would I advice to someone starting on it. We had a good discussion at length & though its been a couple of months since then, I thought I’d share my insights here as well.

Basics:

The usual basics and good development practices apply here as well, so keep them in mind. WordPress has documented & sane coding standards, so make sure you understand & follow them. Other basic principles like DRY, KISS, etc. also apply. If you don’t already, then document your code. Use code comments extensively, document each function and every complex code block.

WordPress has a lot of conditional tags and a good documentation to show their usage. It also has a number of data validation functions. Make use of them.

An important thing to keep in mind is that WordPress loads mu-plugins first, then the active plugins and then active theme is loaded. Refer to the following chart to see loading sequence for different building blocks:

Themes:

Any hooks you want to leverage, any theme functionality you want, it should all go in functions.php of your theme. If the feature has bigger codebase then ideally you should spin it off as a theme plugin. People usually put in a bunch of functions in functions.php, smart ones add namespace prefix to these functions to avoid name collisions and wise developers encapsulate these functions in a static class inside functions.php to provide a namespace and still have sane function names. So instead of this:

php
…hemes/my-theme/functions.php

  1. function my_theme_setup_thumbnails() {
  2.     //.....
  3.     //.....
  4.     //.....
  5. }
  6. add_action( 'after_theme_setup', 'my_theme_setup_thumbnails' );
  7.  
  8. function my_theme_enqueue_scripts() {
  9.     //.....
  10.     //.....
  11.     //.....
  12. }
  13. add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_scripts' );
  14.  
  15. function my_theme_some_feature( $args = array() ) {
  16.     //.....
  17.     //.....
  18.     //.....
  19. }

following approach is much better:

php
…hemes/my-theme/functions.php

  1. class My_Theme {
  2.     public static function init() {
  3.         add_action( 'after_theme_setup', array( 'My_Theme', 'setup_thumbnails' ) );
  4.         add_action( 'wp_enqueue_scripts', array( 'My_Theme', 'enqueue_scripts' ) );
  5.     }
  6.  
  7.     public static function setup_thumbnails() {
  8.         //.....
  9.         //.....
  10.         //.....
  11.     }
  12.  
  13.     public static function enqueue_scripts() {
  14.         //.....
  15.         //.....
  16.         //.....
  17.     }
  18.  
  19.     public static function some_feature( $args = array() ) {
  20.         //.....
  21.         //.....
  22.         //.....
  23.     }
  24.  
  25. //end of class
  26. }
  27.  
  28. My_Theme::init();

If you have some template code that is repeated in multiple templates then don’t put it in the functions.php, that’s not the correct place for it. Make a template part using that template code which you can then load using get_template_part() function.

If you use any (global) plugin functions in your theme then you should always check for their existence before using them. That way your theme wouldn’t break if you de-activate that plugin in future.

Plugins:

Ideally, plugins should not be dependent on your theme code. They’re supposed to work irrespective of which theme you have activated. These can vary from plugins that add some functionality to your site, enhance admin or front-end UI, provide shortcodes for use, etc.

Generic vs Local

But what if you make some plugin and it is tied in with your current theme and is not going to work if you switch to different theme? In such a case, the plugin should be local to your theme and should reside in the plugins directory inside your current theme directory. You will need to load this plugin in your current theme’s functions.php using PHP’s plain old require_once(). This would mean that you are loading it as a library and WordPress plugin activation/de-activation hooks won’t be available, which you shouldn’t be using anyway.

Related: Why not to use WordPress plugin activation/deactivation hooks

The only plugins that should be in your wp-content/plugins directory are the generic type which would work irrespective of which theme you use. You should not be using any theme code or API in your plugins, because if you do then that is not a generic plugin anymore but a subset of your theme and hence should reside in that theme’s directory.

MU-Plugins:

These are the Must Use Plugins, located in wp-content/mu-plugins directory. These are always loaded by WordPress and the only way to disable any of these is to remove that plugin from mu-plugins directory. If you have a code library that you want to use throughout on your site, independent of any plugin or theme, this is the place to drop it in. But there’s one big problem with mu-plugins and how WordPress loads them. Unlike generic plugins, you cannot have mu-plugins organized in their individual sub-directories inside mu-plugins directory, because WordPress will load only those PHP files which are in the root of mu-plugins directory. So to bend WordPress to your will & make it load plugins from their own sub-directories, you need a proxy loader which will be a single PHP file in the root of mu-plugins directory. So something like this should do the trick:

php
…/mu-plugins-proxy-loader.php

  1. function mu_plugins_proxy_loader() {
  2.     $mu_plugins_dirs = scandir( WPMU_PLUGIN_DIR );
  3.  
  4.     foreach( $mu_plugins_dirs as $dir ) {
  5.         $plugin_dir = trailingslashit( WPMU_PLUGIN_DIR ) . $dir;
  6.         $plugin_file = trailingslashit( $plugin_dir ) . $dir . '.php';
  7.  
  8.         if( is_dir( $plugin_dir ) && file_exists( $plugin_file ) ) {
  9.             require_once( $plugin_file );
  10.         }
  11.  
  12.         unset( $plugin_file, $plugin_dir );
  13.     }
  14. }
  15.  
  16. mu_plugins_proxy_loader();

This will run through all sub-directories in the mu-plugins directory and load the bootstrap file of each plugin which should have same name as plugin sub-directory. You can grab this mu-plugin loader from here.

WordPress Development Helpers:

To help development on WordPress, I use & recommend the following tools:

End Notes:

At Barcamp Delhi 9, I gave a talk titled Anatomy of a WordPress plugin. Though it was aimed more at those starting out development in WordPress, I’d advise taking a look at that slide deck as well.

Feedback, as always, is welcome. 🙂