Document your plugins interface (in code)

Edward Bock
Write better WordPress code
4 min readNov 22, 2020

First thing I do when the requirements of a new WordPress project are defined or if the requirements of an existing instance change: I start a research in the plugins repository. There are so many good plugins that can save us so many hours of work and we don’t need to reinvent the wheel. And yes, there are at least the same amount of plugins that I would personally never install in any of my projects. One of the arguments for or against the use of a plugin is the provided interface.

What I mean by the term “interface” of a plugin is how good I as a developer will be able to adapt the plugins features to the ideas (and future ideas) of the project. Typically a WordPress plugins interface consists of a bunch of functions, hooks (actions or filters) and templates. Documentation is hard and it is even harder to keep it up to date. That’s why I plead to start the documentation in code. But how do I document the interface of a plugin in code?

We will use PHP namespace in the code examples. If you wonder why please check Use namespace in plugins and themes.

Functions

You cannot stop developers from misusing your plugins internal functions. Even those that you didn’t plan to expose to public. But you can explicitly create a place for all functions that you want to offer for use to developers.

<?php // plugin-name.phpnamespace MyPlugin;/**
* Plugin Name: YOUR PLUGIN NAME
*/
...require_once dirname(__FILE__)."/public-functions.php";
<?php // public-functions.phpfunction my_plugin_public_fun(){
return \MyPlugin\some_function();
}

I tend to provide these functions in a very traditional WordPress manner. So no namespace but function prefix. This makes it easy even for unexperienced developers to use these functions in combination for example with StackOverflow.com or WordPress.org Developers Handbook code examples like function exists best practice.

These functions in public-functions.php file are treated specially because they are planned to be used in other plugins or themes. That’s why there will be no function renames and no signature changes. Function deprecations will be announces with the PHP @deprecation annotation and these functions will only be removed with the next major release version of the plugin.

Hooks

Every plugin has a main PHP file which is the starting point of the plugin. This is a good place to provide the interface in code documentation for your plugins hooks.

<?php // plugin-name.phpnamespace MyPlugin;/**
* Plugin Name: YOUR PLUGIN NAME
*/
const FILTER_CHANGE_THINGS = "my_plugin_change_things";
// ... more filteres
const ACTION_DO_THINGS = "my_plugin_do_things";
// ... more actions
...// somewhere in your plugins code$args = [];
$args = apply_filters(FILTER_CHANGE_THINGS, $args);
do_action(ACTION_DO_THINGS, $args);
...

Use the prefix FILTER_ for all filter name constants and ACTION_ for all action name constants. So now if you open the main PHP file you have an overview of all actions and filters that are available in the plugin. If you use an IDE like PHPStorm you can even jump to all lines of code where those hooks take effect and what parameters are provided.

Templates

It helps a lot if a plugin provides a way to customize its frontend or backend html output. This can be documented in two steps.

Step 1. Constants

<?php // plugin-name.phpnamespace MyPlugin;/**
* Plugin Name: YOUR PLUGIN NAME
*/
const TEMPLATES_THEME_PATH = "my-plugin";const TEMPLATES_TEMPLATE = "template.php";
const TEMPLATES_TEMPLATE_BY_POST_TYPE = "tempalte-%post_type%.php"
...

Step 2. Default templates

Create a folder “templates” in your plugin and add all base templates that you use there.

One could argue about whether it is necessary to explicitly add a constant for the theme path. Why not just use the plugins name as a convention like WooCommerce does. But there is no official recommendation to do that and other plugins have totally different approaches so in my opinion an explizit in code documentation via constants is the better way. And by the way you would need to use this template path string in your plugin anyway so put it here and use this one.

The exact same argument applies to the template file constants. In addition this can be very useful if you implemented template variations for some value like the post type or template inheritance.

Plugin interface

The complete in code documentation for our plugin interface is now readable in two PHP files. I think that’s clearly arranged.

plugin-name/
templates/
template.php
plugin-name.php
public-functions.php
<?php // plugin-name.phpnamespace MyPlugin;/**
* Plugin Name: YOUR PLUGIN NAME
*/
const TEMPLATES_THEME_PATH = "my-plugin";const TEMPLATES_TEMPLATE = "template.php";
const TEMPLATES_TEMPLATE_BY_POST_TYPE = "tempalte-%post_type%.php"
const FILTER_CHANGE_THINGS = "my_plugin_change_things";const ACTION_DO_THINGS = "my_plugin_do_things";...require_once dirname(__FILE__)."/public-functions.php";
<?php // public-functions.phpfunction my_plugin_public_fun(){
return \MyPlugin\some_function();
}

Write documentation!

Don’t get me wrong. This is no replacement for a developer documentation. So if you plan to open source your plugin you should definitely write a good documentation. But I bet you’ll find it a lot easier if you have a “in code interface documentation” like this.

If you write a project specific plugin that’s only used by you and your team you could completely get rid of the need for any additional documentation. At least that’s what I experienced.

--

--