If you’ve ever written a line of code before, I’m sure that the following scenario has reared it’s ugly head at some point in time. For one reason or another, you need to revisit code that you wrote in the past. Perhaps you remember writing something like this:
<?php
function super_awesome_mega_rad() {
/*
Beautiful code that solves all my problems.
Good job buddy!
*/
}
?>
But when you open the file and scroll to the appropriate line you see something that looks like this:
<?php
function super_crappy_ultra_mess() {
/*
WTF?!?!?!
Who wrote this crap?
Oh, I did.
I DID?!?!?!?!
headdesk
grumble ... grumble ...
*/
}
?>
Personally, this has happened to me more than once and the only thought that goes through my mind at times like these is “What the hell was I thinking?”.
This is a great question that demands to be answered! Providing inline documentation with your code is a great way to answer this question, not only for yourself, but everyone else who uses your theme.
While I was creating Ghostbird, the process of documentation became really, really clear to me and I would like to share my thoughts about the process I use to document my files.
WordPress core uses PHPDoc style syntax to document core and I use it in all my plugins and themes. It’s good to keep things consistent! If you are new to phpDoc, you can read all about it here: http://manual.phpdoc.org/
In the scope of a theme, I found that two types of docBlocks were needed to provide the level of documentation necessary to communicate everything that I wanted. These include page-level docBlocks and function-level docBlocks.
Page Level
I felt that it was important to include a page level docBlock in every php file in my theme. This way I could clearly communicate the intended purpose of the file to the users. I used a subset of available phpDoc tags to accomplish this task. Here’s what I used in my theme’s header.php file:
/** * Header Template * * This file is responsible for generating the * top-most html for all public-facing views. * It's content is generated via core WordPress * functions as well as custom actions defined * in functions.php. * * Child themes are encouraged to work with the * actions defined herein to add or remove data * to/from the top of the template. In the event * that the html needs to be modified, this * template may be duplicated inside a child theme * and edited there. Please note the this file * leaves 2 html div tags open. Both of these tags * are properly closed in footer.php by default. * * @package Ghostbird * @author Michael Fields <michael@mfields.org> * @copyright Copyright (c) 2011, Michael Fields * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License * @since 1.0 * @alter 1.1 * * FUTURE RELEASE * @todo Add widget area. Intended for search form? */
Title
More times than not, I just used the name of the file with the extension removed.
Description
In my opinion this is the most important part as it serves to communicate the intention of the file. To figure what to include in the description section for each template file, I did my best to answer the following questions:
- In which context is the template used?
- How is the template best modified in a child theme?
- Does the template use custom hooks?
- Does the template leave any html tags open that are closed in another template?
Meta tags
- @package
- This should be unique to your theme. In my opinion, only themes that ship with core should use the term “WordPress” here. Unless your theme is part of WordPress core, you should not use “WordPress” as your package name.
- @author
- This tag should include your name and, optionally, email address. In the event where multiple authors were responsible for writing code in the document, you can add multiple @author tags.
- @copyright
- This line should include the name of the copyright holder as well as the year the file was created.
- @license
- Used to communicate the license that your file is released under. It is a really good idea to include a link to the license as well.
- @since
- When was the file introduced into the package. This tag should reflect the version number of the theme.
- @alter
- This tag is not part of phpDoc. Quite honestly, I just pulled it out of thin air. I include this in all of my docBlocks so I can easily tell when the file was last modified.
While it may seem redundant to include all of this meta information in every single file, I feel that it’s better to be as explicit as possible.
Todo tags
The fourth and final section is totally optional but can be especially helpful. First of all, it will show users what you intend to do in the future. If you process all of your source code through a program like phpDocumentor, it will create a list of all todo items for your project … all in a single page! This can be really useful to see what needs to be done for the next version of your theme without having to dig through all the files.
Function level.
Function level docBlocks are used immediately before each function’s definition. While they are similar in appearance to page-level doc blocks, they serve a different purpose: To document the use of a single function. Here’s an example of a function from the Ghostbird theme:
/**
* Append edit link to content.
*
* Certain post formats (aside, link and status)
* do not display meta information at the bottom
* of the entry box. While this makes them more
* compact, it also removes the helpful edit link.
* This function will add the link inside the_content
* before wpautop() fires and after the [link] link
* is appended.
*
* @param string Post content.
* @return string Custom post content.
*
* @access private
* @since 1.1
*/
function _ghostbird_content_append_link_edit( $content ) {
if ( is_single() ) {
return $content;
}
$url = get_edit_post_link();
if ( empty( $url ) ) {
return $content;
}
$format = get_post_format();
if ( in_array( $format, array( 'aside', 'link', 'status' ) ) ) {
$content .= ' <a class="post-edit-link auto-link" href="' . esc_url( $url ) . '" title="' . sprintf( esc_attr__( 'Edit this %1$s', 'ghostbird' ), ghostbird_post_label_singular() ) . '">' . esc_html__( 'edit', 'ghostbird' ) . '</a>';
}
return $content;
}
When documenting a function, I visually separate the docblock into four distinct sections. The first two sections are very similar to the page level docblocks and contain:
Title
Most of the time the name of the function (minus the unique prefix) works well here. I try to make this as short as possible.
Description
Quite possibly the most important part. In my opinion, this section should clearly state the intention of the function. Why was it created? If the function is intended to be hooked into WordPress, it is probably a good idea to include this information as well. In the event that the function declares it own custom hooks, the description is the perfect place to let users know how they can customize the function without altering it. phpDoc supports the inclusion of simple html tags, one of which is code. In most of my recent projects, I’ll include mini tutorials complete with code examples which users can copy and paste into their child themes. There is a lot that can be accomplished in the description of a function-level docBlock. I intentionally try to make them as long as possible.
Input + Output
This section is used whenever a function accepts input via parameter and/or returns a value. Two phpDoc Tags are used in this section:
- @param
- A line starting with the
@paramtag should be used to document each parameter accepted by the function. These lines should be listed in the order in which they are passed to the function. Each line should contain two pieces of information. The first defines the type of variable that the function expects. The second is meant to describe the data. So-called named arguments (a single associative array whose keys are recognized by the function) present an interesting challenge here. While I would agree that they should be represented in this section, I have not found a decent way to list all recognized keys here. Quite possibly the cleanest solution would be to list all recognized keys in the description. - @return
- This tag is used to document that return value of the function. It uses the same format as the
@paramtag: Value 1 = data type & Value 2 = description of the data. Not every function returns a value though and in cases like this I will set the data type tovoid. Sometimes I will use the “data description” section to document what the function does, but often I omit this if it is sufficiently explained in the description.
The last section that I always add includes the @since and @alter tags that I covered above as well as a new one: @access. If a function should not be directly used in the theme, I tag it as “private”. In cases where the user is free to place a function in a template file, I tag it as “public”.
And optional section for @todo can be added on the function level as well.
Naming Conventions
As you may already know, it is very important to create a unique prefix for all of your functions. This should be simple and unique. My theme is named “Ghostbird” so I used the prefix “ghostbird” at the start of all of my functions. I also started to adopt a naming convention that I picked up by reading core. WordPress has many “private” functions. While I don’t know the reason why each individual is marked as private, I do know that I shouldn’t really use them in my extensions. Most of these functions start with an underscore.
I think that this is a great idea! So I wanted to use it to. Looking over all of the custom functions that I created for my theme, I noticed that there were 3 specific types of functions existed:
- Template Tags
- Hooks (action and filter callbacks).
- Callbacks passed to core-defined template tags.
I decided that Template Tags would be labeled as public meaning that these functions are free to be used in template files. Tagging a function as public also meant that the function could never be removed from the theme.
Hooked Functions would definitely be tagged as private meaning that they should never ever be used anywhere. If end users follow instructions and do not use these functions, then they can easily be deleted in future releases.
Callbacks are rather interesting as they embody properties of the previous two types. They need to be used directly in template files, but never alone. Functions of this type have been specifically designed to be passed to a core-defined template tag. I originally made the mistake of tagging functions of this type as “private” I now feel like they would better be tagged as “public”.
In Conclusion
While I do not use all of the tags supported by phpDoc, I have found that ones listed here are absolutely indispensable to provide useful documentation. This article represents my personal opinion and should be treated as such. I think that documentation is an integral part of any project and am always happy to see in when looking over source files. That being said, I do not feel comfortable defining rules for others to follow. Basically, I would prefer documentation in any form over no documentation at all.
Please let me know any thoughts in the comments section!



I know I’ve certainly come to old code and wondered if it was really me and what I was on at the time. Really solid inline docs is what I think is missing from most projects. Even WordPress could be better IMO. Yes the functions are documented but I’d love to see it be more clear in line so that someone just starting to dig in to WordPress has a reduced cognitive load when reading through the code.
No adding so many comments that every beginner can read every line is pushing it but I think that a bit more should be done.
Curtis, I definitely agree with you that core could be documented much better and it might be a great way to contribute to core. After talking with Nacin at WordCamp Seattle about how core development works, I learned that I should take more initiative to get code committed. I think a great way to help out would be to fix errors and holes in whenever I come across them. If enough of us start doing this, core documentation should improve quite rapidly. I’m game if you are :)
Overly documented core annoys me as well. On another note, I do find myself writing line-by-line docs some times. IMO if it clearly communicates my intention, or I feel that it would be beneficial to “future me”, I would rather have it there than omitted.
Hahahaha
I go through that ‘who wrote that crap’ every day. The problem is I am still the problem… LOL
great post.
Great writeup. I’ve been trying to improve my inline documentation for a while now. I’m sure it’s not as good as it could be, but I do my best!
I find the inline documentation in Justin Tadlock’s Theme Hybrid to be the easiest to read and try to follow that as a model for my own code.