3. WordPress Plugin Structure
When we plan to develop and release a production level WordPress Plugin, we have to follow certain best practices suggested by WordPress and also by other accomplished Plugin developers. WordPress Plugin structure as to follow some well defined layout.
In this section, we show how to structure a WordPress Plugin and also highlight some of the coding standards that makes the plugin easy to maintain and increase readability.
Share on Social Plugin.
Here onwards, we go through Share on Social Plugin project. Download the complete Share on Social Project from GitHub which contains plugin code and also the unit tests.
It is an Eclipse ready project which we can import to Eclipse as a existing project. But, you can also use it with any other PHP IDE.
Enable WP_DEBUG
WordPress strongly recommends to enable WP_DEBUG while developing
themes and plugins. When enabled, WordPress outputs all notices,
warnings and errors to a log file debug.log
in wp-content
directory.
Debug log catches many subtle warning and errors which otherwise may go
unnoticed by the developers.
To enable debug, edit WordPress configuration file wp-config.php and add following lines.
/opt/lampp/htdocs/wordpress-4.0.1/wp-config.php
/**
* For developers: WordPress debugging mode.
*
* Change this to true to enable the display of notices during development.
* It is strongly recommended that plugin and theme developers use WP_DEBUG
* in their development environments.
*/
@ini_set(‘display_errors’,0);
define('WP_DEBUG', true);
define('WP_DEBUG_DISPLAY', false);
define('WP_DEBUG_LOG', true);
define('SAVEQUERIES', true);
/* That's all, stop editing! Happy blogging. */
To test proper WP_DEBUG configuration, place a error_log('some message');
in share-on-social.php and open the site in the browser.
WordPress outputs the message to the log
file/opt/lampp/htdocs/wordpress-4.0.1/wp-content/debug.log.
Keep tab on debug.log
During development, check the debug.log regularly and fix the errors and warnings When done so, it is quite easy to fix the errors and keep the plugin healthy.
In case we plan to host the plugin on wordpress.org, approval may not happen when there are unfixed warnings and errors in the log.
Define constants
Throughout the plugin, we often refer some paths and constants and
normally, they are defined at the start of plugin in the main file. In
Share on Social, we define them in its main file share-on-social.php
share-on-social/share-on-social.php
define( 'SOS_NAME', 'share-on-social' );
define( "SOS_VERSION", '1.0.0' );
define( "SOS_URL", trailingslashit( plugin_dir_url( __FILE__ ) ) );
// plugin path
define( "SOS_PATH", plugin_dir_path( __FILE__ ) );
//basename share-on-social/share-on-social.php
define( "SOS_PLUGIN_BASENAME", plugin_basename( __FILE__ ) );
// main file - share-on-social.php
define( "SOS_PLUGIN_FILE", __FILE__ );
We start all constants with SOS_ so that names don’t clash with constants from other themes and plugins. Always prefix the constants with the plugin name or some unique abbreviation.
Functions and Class Files
It is easy to code the plugin functionality with PHP functions. But this approach may results in function name conflict either with functions defined by site theme and other active plugins or even with WordPress API.
Even though bit difficult, better approach is to use PHP Classes which allow us name the methods without the name conflict.
For Share on Social, we use classes for all modules except the main plugin file. In the main file, we use regular functions. Rest of the functionality are split into class files which are included in main file.
Let’s see how this is done with two class files; one for front end and another for admin module. In the following code snippet, we include two class files class-frontend.php and class-admin.php.
share-on-social/share-on-social.php
// plugin entry point
setup_sos_plugin();
function setup_sos_plugin () {
require_once SOS_PATH . 'include/class-helper.php';
if ( is_admin() ) {
require_once SOS_PATH . 'admin/class-admin.php';
add_action( 'plugins_loaded', 'load_sos_admin' );
} else {
require_once SOS_PATH . 'frontend/class-frontend.php';
add_action( 'plugins_loaded', 'load_sos_frontend' );
}
}
function load_sos_admin () {
$sos_admin = new Sos_Admin();
$sos_admin->setup();
}
function load_sos_frontend () {
$sos_frontend = new Sos_Frontend();
$sos_frontend->setup();
}
In the main file, we call a single function
setup_sos_plugin()
which is also the starting point of the plugin.In the function, we check whether we are in admin screen or in site with the help of
is_admin()
. WordPress function is_admin() checks whether we are in the Admin panel. Please note that we should not use this function to check whether the user has admin privileges or not.If we are in admin screen, then include
class-admin.php
and then attachload_sos_admin()
function to WordPress hook plugins_loaded usingadd_action()
. We explain add_action() in the next blog but for the time it is suffice to note that when all active plugins are loaded, WordPress calls the function load_sos_admin().In
load_sos_admin()
function, we create a object of classSos_Admin
and call itssetup()
method.We do similarly with class-frontend.php, if
is_admin()
is false.
It is important to note that load_sos_admin()
and
load_sos_frontend()
are not called immediately by add_action in
setup_sos_plugin()
, but their execution is deferred. Just for the sake
of explanation, we split this into two phases. When we access the site,
as part of phase one, WordPress processes all activated plugins. When
share-on-social.php
is processed its setup_sos_plugin()
function is
called. In this function, WordPress includes the class files and calls
add_action() which just registers load_sos_admin()
and
load_sos_frontend()
as callback functions with WordPress for a
hook named plugins_loaded. Then WordPress goes on to process other
plugins which are active in the site. When all active plugins are
processed, WordPress triggers second phase by calling the hook
plugins_loaded. At this point, WordPress calls registered callback
methods load_sos_admin()
and load_sos_frontend()
and execute code
contained in them.
Next, let’s go through a plugin class file to see how classes are defined with a snippet from class-frontend.php .
share-on-social/frontend/class-frontend.php
<?php
defined( 'ABSPATH' ) or die( "Access denied !" );
class Sos_Frontend {
var $sos_shortcode = 'share-on-social';
public function setup () {
// enable shortcode
add_shortcode( $this->sos_shortcode,
array(
$this,
'enable_sos_shortcode'
) );
}
// other methods of the class
}
In the class file, we define class Sos_Frontend
and its method. First
define variables which have class scope such as $sos_shortcode
. In
class, we use setup()
to carry out initializations tasks such as add
actions, filters, shortcodes and also to include other class files and
modules etc., All class files of the plugin follow similar pattern. At
this stage, it is enough to comprehend the overall structure of plugin
and its files as we cover the code in detail throughout the tutorial.
WordPress Plugin Structure
The layout or directory structure of the plugin is shown in the screenshot.
top level directory - contains main file share-on-social.php and also uninstall.php which is used to uninstall the plugin. It also contains a build file to zip the plugin, unit test configuration files. The file readme.txt is mandatory when we plan to host the plugin on http://wordpress.org/plugins directory.
admin - directory holds class files related to admin module.
css - contains CSS files of the plugin.
frontend - contains front end class files.
images - directory to hold images and icons used by the plugin.
include - helper and util classes used by plugin.
js - holds JavaScript files.
langs - language translation files for internationalization.
tests - phpunit and qunit test files.
dev - files in this directory are not part of the actual plugin but related to development process such as Eclipse Code Formatter for WordPress and other stuff related to developments.
There is no hard and fast rules about directory structure. We just took it from other leading plugins and developer is free to adjust the structure as required.
File and variable names
WordPress recommends Coding Standard to follow while contributing to WordPress core. Even though they are not mandatory for plugins, we prefer to use them for plugin development to improve the readability of the code.
We use - (dash) in file names as in class-admin.php
and prefix
class- to files to denote that they are class files. For variables,
functions and methods, we use _ (underscore) as in $share_name
. In
JavaScript, for functions and variables we use camel case as in
processLockers()
.
Eclipse Formatter Profile.
WordPress PHP Coding standard recommends a list of formatting standard
like quotes, indentation etc., Projects’ dev directory contains Eclipse-Formatter-PHP-for-Wordpress.xml
which sets many of the
recommendations.
If you are using Eclipse, you may import the profile using Project Properties → Code Style → Formatter → Import.
In the next chapter, we go through plugins main file and also explain the benefits of PHP Classes.