In August 2008 I made a quick review of 50 plugins (part 1, part 2) and was really surprised by the number of coders who ship plugins with barely readable code. Working, even clever, but ugly code.
Making clean sources is not a useless mania of a compulsive obsessive geek, it's truly a requisite for maintainable code. It won't make your code good — just better.
For less experienced coders here are a few rules of thumb I try to follow. That's just my word and my coding habits, nothing is to be considered as the definitive best practice, but I hope this will make anyway a good pointer for novices.
Good Plugin Habits: Make clean and readable sources
As a WordPress plugins coder, mostly everything I know, I've learnt it by reading sources: find about a plugin that does something, wonder how I would do that or even how such a thing is possible, then read the plugin source to compare their solution and mine, or even just learn about a new trick, a new API or a function I didn't know about. I barely read instructions or readmes, but I always read the sources.
And as a WordPress plugins releaser, I maintain a number of scripts. I wrote some of them four years ago, and anyway most of the time when I haven't worked on a plugin for more than a couple of months, I totally forget how I coded it. Maintaining plugins means updating them once in a while: either someone finds a bug, or the WordPress code and APIs evolve in a way that breaks the plugin, so I have to rewrite parts of it. Basically, this means rediscovering my own plugin: read the sources, wonder how I did this and why I did that. Needless to say, this is much less cumbersome if the source is clean.
To me, making clean sources is twofold: help others reading my code, but primarily help the future-me maintaining outdated stuff. If someone finds your source hardly readable, you will too.
This said, how do you keep your plugin sources tidy and clean? Nothing rocket science and just common sense, really:
Indent your code
When reviewing a couple dozens of plugins for the Plugin Competition 2008, I was truly shocked by the number of coders who don't indent correctly, or consistently, or even who don't indent at all.
I've seen several bits like the following:
- if ($bool) {
- foreach ($vars as $var) {
- if (check_var($var)) {
- $that = process_var($var);
- return ($that);
- } else {
- do_collect($var);
- }
- }
- return false;
- } else {
- return true;
- }
How ugly is that? A few in-front tabs would make things much more readable, helping identify where blocks start and end.
Be descriptive
For most of the code, things are self explanatory if well named. Reading a block of PHP code should be almost like reading basic English. A loop increment can be named $i, but give all your function and variables a name that will unmistakably tell the reader what they do or what they are for.
Ugly: joe_check($string1, $string2)
Cool: joe_check_and_validate_inputs($username, $password)
Comment the source
Don't state the obvious : don't comment trivial things (everybody will understand what function myplugin_create_default_database() is for) but you have to add some insight to its tricky parts. Comments are not there to turn your work into a coding tutorial where you explain the basis, you write comments primarily for you.
When reading a code block, one should understand all of the 3 following key points:
- What: the aim
- How: the method
- Why: the reason
The What and the How may not require even require comments. Sometimes, giving the function a self explanatory name will be enough.
The How could either be a detailed comment at the beginning of the block, or several one liners inside it, before each key part (that should be visually separated by a blank line)
The Why is really the crucial part. Whenever you're making a design choice, this has to be explained and justified, for two reasons. First, you'll want to understand a tricky bit of code in 2 years when you read it again. And second, you'll want to be able to understand the reasoning behind this decision, and eventually be able to make another, and hopefully better, design choice. Whenever you spent some time in your code on a problem, spend an extra minute explaining how you handled it.
Bonus: special comments
PHP supports various types of comments, either inline or blocks, such as:
- // this function will do ....
- function something($var) {
- $var = somefunc($var) // inline comment
- /* Now we have to sanitize
- and make sure that ...
- */
- ...
- }
A comment can be really anything you feel comfortable with: brief explanations, more detailed stuff, formal or informal, as long as it doesn't make your code slower to read (explain, don't distract). Still, there is a rather widely adopted convention over a few keywords in comments, and amongst them: TODO: and FIXME:
- TODO: indicates that a part can be extended, adding features for instance. Additional code should go here at some point of the development.
- FIXME: shows parts that must be improved: fix a bug or potential bug, rewrite a time consuming loop…
Leave these comments as notes for the future you or for someone else.
Another set of strange keywords you'll find, in most of WordPress' core files now, are what is called Javadoc. These look like the following:
- /**
- * do_action() - Execute functions hooked on a specific action hook.
- *
- * @since 1.2
- * @param string $tag The name of the action to be executed.
- * @param mixed $arg,... Optional additional arguments
- * @return null Will return null if $tag does not exist in $wp_filter array
- */
- function do_action($tag, $arg = '') {
- ...
This standard way of commenting allow some tools to generate automated documentation (see image here) and also enforces attention to details and strictness when coding: did I provide a function description? Am I sure it will only accept strings? Will this always return a boolean?
This comment syntax is really valuable on larger team projects, but I find it a bit overkill for my personal plugin coding needs.
Split in several files
Make several smaller files instead of one big file, group functions in different files by topic, as this will have several virtues
First, it makes things prettier, which will make you prouder. As simple as this :) One short main plugin file, and various directories for images, CSS, javascripts, PHP includes, translation files,…
Second, when a particular WordPress API evolves and breaks your plugin (and this will happen), you'll know which small file needs work: the one with comments function, the one dealing with the admin interface? It's much less burdensome to rework a tiny homogenous file than a big one.
Third, split for performance. Making various small files will allow you conditionally include them only if they are needed. For instance, group all the admin interface functions in plugindir/includes/admin.php and in your main plugin file where the plugin initializes everything use something like:
- if (is_admin()) {
- // we're in wp-admin/
- require_once(dirname(__FILE__).'/includes/admin.php');
- }
Stick to one syntax
Once you are comfortable with a coding style, stick to it. If you prefer to indent with 4 spaces instead of 1 tab, naming with CamelCase (joeCreateDatabase() or underscore separation (joe_create_database()), putting curly brackets before of after a line break… it's all up to you, as long as you're consistent across your files.
As reference, the adopted coding style for WordPress core files seems to be:
- <?php
- function do_something ( $var1, $anothervar ) {
- $foo = $var1; // this is $foo
- $foo34 = $anothervar; // this is $foo34
- if ( $condition ) {
- do_this();
- do_that();
- }
- if ( 'foo' == $bar )
- do_foo();
- 'something' == $foo;
- }
- ?>
That is:
- No shorthand PHP start tags (<? … ?> or <?=$var?>) but full PHP tags (<?php … ?>)
- Lowercase and underscore function names
- Spacing before and after parenthesis, and between parameters
- Real tabs in front, and spaces to align elements where that improves readability
- Braces used for multiline blocks but avoided when possible (single line)
- Variables on the right side of logical comparisons
Group hooks
My personal preference is to group hooks (add_action() and add_filter()) all together at the end of the main plugin file, rather than spread all over the file. I've found that it makes things a lot easier when you try to figure out what's going on, and what is the typical "flow" of events, especially when they refer to aptly named functions.
References and More to Read
- Common sense
- Wasted hours because of crappy code on first iteration :P
- WordPress Coding Standars and a mail by Mark Jaquith on coding style
- Successful Strategies for Commenting Code
- 13 tips to comment your code
- Naming conventions in programming on Wikipedia
Shorter URL
Want to share or tweet this page? Please use this short URL: http://ozh.in/ln
I can't believe I finally found someone using my very same coding style! And it's WordPress coding style, nonetheless!
I'm just learning from this WordPress world, but I expect to make something really awesome out of it!
Thanks for these tips!
Thanks for your articles, this will be my second year working on WordPress Platforms, and thought I'd do some refreshers to start the year on the right foot. Love your tips, easy to read, and understand. Great resource.
best
SCm
I'd like to add another important (IMHO) readability guideline…
"Avoid unnecessary levels of indentation by dealing with potential failure scenarios first and then moving on to the success scenario."
I see too many developers writing code whereby they only check for success scenarios, leaving failure scenarios to 'else' blocks further down the code, which are increasingly difficult to match to the original condition, especially where indentation isn't consistent (i.e. mixes tabs and spaces!).
The idea is not to put huge chunks of code in ever-increasing levels of indentation. Use 'continue' to move on to the next iteration of a loop if conditions haven't been met. Use 'return' early on in functions if conditions haven't been met.
For example:
The above could easily be written more clearly and concisely as…
function do_something() {
$test1 = some_function();
if ( $test1 != 'ok' ) {
echo "Test1 failed";
return;
}
$test2 = other_function();
if ( $test2 != 'ok' ) {
echo "Test2 failed";
return;
}
actually_do_it();
}
[/php]
Rule of thumb: If your code reaches any more than 4-5 levels of indentation at any point, you should consider breaking it down into smaller functions.