WordPress plugins require a number of headers to be included in the plugin file for them to render correctly in the dashboard. If releasing a plugin on WordPress.org then a number of additional headers are required in the readme file.
The problem I have is that I can never remember which header goes where. Each time I write a plugin, I have to spend time reading the docs and making sure everything is in the correct location.
Unit tests would be dandy 🌻
When I worked at Nine Publishing, the comment I became known for on pull requests was one line: unit tests would be dandy. Without a dandelion emoji, my colleague Chris would react each time with the sunflower emoji.
It eventually reached the point that I could drop the comment 🌻 and the message was clear.
As I was recently working on a plugin and once again reading the readme and plugin header documentation it occurred to me: sunflowers are the answer. Unit tests would be dandy.
What headers are required?
There’s a lot of headers required, or–at least–recommended, when putting together a plugin for publishing on the WordPress.org repo. In alphabetical order they are:
- Author URI
- Author
- Contributors
- Description
- Domain Path
- Donate link
- License URI
- License
- Network
- Plugin Name
- Plugin URI
- Requires at least
- Requires PHP
- Requires Plugins (if there are plugin dependencies)
- Stable tag
- Tags
- Tested up to
- Text Domain
- Update URI
- Version
Some of these are only used by WordPress.org; some are used by WordPress for the plugins screen and plugin updates; and some are used for all of these purposes.
After a brief search I was unable to find any existing code to test the plugin headers. I decided to write my own tests and include them in my plugin template repo.
Header categories
While my unit tests are slightly opinionated, I’ve decided to categorise them for each file as one of three things: required, optional or forbidden.
The forbidden characterisation is the most opinionated, adding a plugin header to the wrong file won’t break anything but it might make things more difficult for the developer down the track.
I based my opinions after reviewing the WordPress.org plugin importer and the code used in WordPress Core.
Readme headers
For the readme.txt
file, I came to the conclusion the following headers were to be included in the file. Optional headers are marked with an asterisks:
- Contributors
- Tags*
- Donate link*
- Tested up to
- Stable tag
- License
- License URI*
All other headers are forbidden from the readme file.
Plugin file headers
For the main plugin file, I came to the conclusion the following headers were to be included in the file. Optional headers are marked with an asterisks:
- Plugin Name
- Plugin URI*
- Description
- Version
- Requires at least
- Requires PHP
- Author
- Author URI*
- License
- License URI*
- Text Domain*
- Domain Path*
- Network*
- Update URI*
- Requires Plugins*
All other headers are forbidden from the main plugin file.
The unit tests
The unit tests are available in my plugin template repository on GitHub. The primary purpose is to test that required plugins are in each file and the forbidden headers are not.
Secondly, they also test that any headers common to both files match, For example, that you’re not claiming your plugin is both MIT and GPL licensed.
Additionally, they also test that the stable tag header in the readme matches the version header in the main plugin file. For plugins that bump versions to -alpha
or -beta
after a stable release, this will cause problems but it suits my purposes.
Early Wins
While writing these tests and reading the code in both WordPress and the WordPress.org importer, I realised that my WordPress plugin template had a few duplicate headers that I could remove from my readme file.
Having removed these headers, I ran my revised readme template through the WordPress.org Readme Validator to ensure it met the requirements with regard to these headers. The message returned was:
The
Requires at least
field is missing. It should be defined here, or in your main plugin file.The
Requires PHP field
is missing. It should be defined here, or in your main plugin file.
As my tests enforce the headers in the main plugin file, that tells me that everything is good to go.
Dandy 🌻
Thank you Aaron Jorbin and Jonathan Desrosiers for their feedback on this post.
Leave a Reply