Published Thursday 15th February 2024

Submitting WordPress plugins and plugin updates

Having recently launched our first WordPress plugin, the Admin Country Allowlist, I thought it would be useful to collate my notes into a tutorial explaining the process of both submitting a viable plugin, and actually maintaining it moving forwards. The WordPress review team are very thorough in their process so it's good to know what to expect from that, and when you do get accepted in, you're a little bombarded with links to various information resources which feels daunting at first, so just collating the important elements from those resources into a single post might be useful. That said, you should definitely still look through all of the resources that the WordPress onboarding email points to, as this post isn't intended to be comprehensive.

How to make a WordPress plugin

Actually building a WordPress plugin is beyond the scope of this tutorial, but just to cover the absolute basics - a WordPress plugin is essentially just a folder in the wp-content/plugins directory, containing at least one PHP code file with a comment section at the top which defines various properties, such as the plugin's name and version, and a readme file containing more properties and some important detail sections. Your code file should have the same name as the folder it's contained in.

As part of the initiation process, WordPress iterates each plugin folder and executes the code file that matches the folder name, so from there on you'd want to use WordPress hooks to add your code to other parts of the system. For example, if you want to add something to the admin panel menu, then you'll probably want to use the add_action() function to add your own callback code in to the admin_menu hook so that WordPress knows to fire it when that part of the admin page is being output. You can otherwise do whatever you like with this code file, and you can nest other code files and assets into the plugin folder as much as you want.

Put simply, when you create a WordPress plugin, all you're really doing is adding your own PHP code to a special folder which WordPress knows to parse early on when serving requests. Check out the Plugin Handbook within the official WordPress developer resources for all of the details, particularly the Plugin Basics section, and also take a look at the code of some simple plugins such as Hello Dolly. There's also a sample readme file to base your own on, and a Plugin Readmes section within the developer resources which explains all of the different sections really well.

How to submit a WordPress plugin

You don't actually have to submit your plugin to the WordPress repository for it to work. As detailed above, a plugin is just any code within the wp-content/plugins folder, so all you really need to do is upload your code to this folder for it to work. You can do so via the WordPress admin panel Plugins -> Add New Plugin page, where you'll find an upload button at the top. Just create a zip file containing your plugin folder and the aforementioned PHP and readme files, and upload that zip to your panel. If all you want to do is add your plugin to your own website, there's nothing at all wrong with this method.

If you've gone to the effort of making a plugin though, it's probably useful to somebody else and if you upload it to the repository, anybody can then add it to their website. They could just download a copy of your zip and upload to their own panel manually, but when you start making updates the manual labour of getting that update out to everybody who you know is using your plugin becomes a chore. If you're in the WordPress plugins repository, WordPress can just automatically pull updated versions itself.

Actually submitting your plugin is the easy bit. Just head over to the WordPress plugin submission form and upload your zip. You'll need a wordpress.org account and this will become the account WordPress refers to as the plugin author, so make sure you're logged in to the appropriate account before upload. Also be careful to name your plugin sensibly before upload because you'll be given a URI based on that name, and both the name and URI will be publicly displayed fairly prominently.

You should read through the Plugin Guidelines and FAQ before submission, and you should validate your readme file. If you haven't already done so, select a GPL compatible license and add that to your plugin too. Don't forget to set the license value in your readme and main code file appropriately.

Once you've submitted your plugin, it goes into a review queue and at the time of this writing, this queue hosted about 20 days worth of plugin submissions waiting to be reviewed. When I submitted our first plugin, the queue had 3 months worth of submissions. If there are any problems with either your plugin code or readme file which you could have easily picked up on yourself before submission, these will be noted by the review team and you'll need to wait for them to get around to reviewing your amends so it's worth being pragmatic and catching everything you can at this stage instead of prolonging the review process unnecessarily.

The WordPress plugin review process

The moment you submit your plugin, you'll be automatically assigned a unique URI based on your plugin name, which doesn't conflict with anything else. If you've named your plugin the same as something which already exists, you'll therefore be assigned a URI with a suffixing integer that's sequentially one more than all of the others with the same name. If you don't like your URI you can at this stage request that it's amended, but once approved this address is set in stone, so now is the time to make sure you're absolutely happy with it.

Now you've to wait, probably a few weeks at the very least, for your submission to be processed. Eventually you'll receive an email from somebody within the review team. If you're lucky, there'll be no issues at all and you'll just receive an acceptance email in to the repository, but honestly this is extremely unlikely. There are so many potential reasons why you might need to amend something that the chances of making it straight through seem slim. For example, I didn't realise wp_remote_get() was a function and had just used Curl requests initially, which isn't allowed. Basically if there's a WordPress function for something, it's apparently required that you use it. WordPress has various sanitisation and validation functions and such which they're going to check that you're using.

If the review team pick up on something that they want you to change, the email will reference the individual lines that are problematic and will link to documentation on how to use particular functions to resolve. Generally, although these emails can look lengthy, it's actually easy to figure out what their problem is and make changes.

Once you're done making changes, package up a new zip and reply to the email with this as an attachment. You're emailing a real person, so you can add information and ask for clarifications etc if need be. With our plugin, I was asked to better reference that our plugin relied on a remote service in the readme file, which I did, but this request was then repeated in a second review and I couldn't understand why. I replied to the second email pointing out all of the references we were making in the current copy of the readme file, and in a follow-up review the reviewer acknowledged that our readme was fine after all and didn't need further amends. Remember that the reviewers are only human and might make mistakes like anybody else, despite the emails you receive following an obviously semi-automated structure.

Eventually, after however much back-and-forth it takes, you'll be accepted in and receive a final email containing various links to all sorts of resources, including information on how to use Subversion (SVN), to upload your plugin. Your earlier upload was to the review team, SVN is how you actually upload to the WordPress plugins repository.

Uploading a WordPress plugin via SVN

At this point, you should have received a password to connect to your SVN repository using. Your repository address is the URI assigned when you originally uploaded your plugin to the review team, and your username is the same as the wordpress.org account you were logged in to at that time.

There are many Subversion GUIs available for various operating systems. It's beyond the scope of this blog post to compare them or explain how any of them work. Instead, we'll stick with the basic SVN commands. If you're a programmer making WordPress plugins, the SVN commandline should be a breeze anyway. The following snippets assume that you're running Linux, but the SVN commands should be the same.

Install the Subversion package via your package manager. For example if you're running Gentoo Linux:

$ sudo emerge dev-vcs/subversion

Subversion is a version control system where you "check out" a local copy of an SVN repository, make changes to your copy, and then "commit", or "check in" those changes back to the repository. It's a powerful tool and if you're working within a team, it's most useful for being able to cleverly merge files that multiple people have made changes to, but an in-depth explanation is beyond the scope of this tutorial. Instead we're just covering the basics, and how WordPress wants you to use your repository.

First off, you'll need to pull the current contents of your new SVN repository into a local folder which you can work from. For the purpose of snippets, I'm using the plugin name foo-bah-plugin, and the wordpress.org username foo-bah-username. Replace with your own values, obviously.

$ mkdir local-foo-bah-plugin
$ svn co https://plugins.svn.wordpress.org/foo-bah-plugin local-foo-bah-plugin

Subversion will pull the files down and within your local folder, you should now see three folders - assets, tags, and trunk.

Within the assets folder, you add your icon, header graphic, and screenshots for your plugin page. There are specific dimensions and file types which you have to use, and a specific filename format for each. Refer to the How Your Plugin Assets Work section of the developer resources for all of the details.

Header images have a maximum file size of 4mb each, and you should upload at least two images as either .jpg or .png files. One for normal screens, and one for retina displays:

  • banner-772x250.png
  • banner-1544x500.png

Optionally, you can upload different header images for different languages by adding a language code to the end of the filename, like this:

  • banner-772x250-es.png
  • banner-772x250-de.png

Icons have a maximum file size of 1mb each, and you should upload at least two images as either .jpg or .png files.

  • icon-128x128.png
  • icon-256x256.png

Optionally, you can upload an SVG version too. This is recommended for crispness, but since some devices don't support SVG natively, you still need the above two as fallbacks.

  • icon.svg

Screenshots have a maximum file size of 10mb each and can be uploaded as either .jpg or .png files. You can upload any number of screenshots, with sequential filenames as per the following. You don't need to upload any screenshots at all but if you do upload some, then you must also populate the screenshots section of your readme file appropriately.

  • screenshot-1.jpg
  • screenshot-2.jpg

Optionally, you can upload different screenshot images for different languages by adding a language code to the end of the filename, like this:

  • screenshot-1-es.jpg
  • screenshot-2-de.jpg

Remember to add an appropriate line to the screenshots section of your readme file for any screenshots that you upload.

The trunk folder is your working release. Essentially, this is the bleedin' edge, development version of your plugin except that you shouldn't commit your changes until you're ready to release, so you shouldn't use the repository as a development copy as such. Work locally, or with another version control system for actual development, and when you're ready to release an update, then commit. For now, use your file browser or regular cp commands to copy your plugin files into the trunk folder. The main PHP file, readme.txt, and license should be in the root of trunk, but you can add whatever other files and folders the plugin needs too.

With everything in place, make sure that that your readme file is up to date:

  • The Stable tag value should be updated to this new version. Version numbers should be x.y.z formatted, where x increments represent breaking changes, y increments represent new non-breaking features, and z increments represent minor changes or bug fixes. Also make sure this tag matches the Version value of your main code file.
  • The Tested up to value should be the latest version of WordPress which you know that your plugin works with. This should be x.y formatted, not x.y.z, because WordPress only increment on the z if making minor changes or bug fixes so if your plugin works in the x.y branch, it should continue to work regardless of what z is. Otherwise if you refer to a specific x.y.z version then when WordPress updates to the next z increment, your plugin will display as untested in that version and keeping up with those updates manually isn't feasible.
  • The Tags value should be set to up to 12 comma separated tags which you'd want your plugin to appear under when people search for those terms. WordPress ignores additional tags and only uses the first 12, so be careful to choose terms that you actually expect people to search for. The first 5 terms will also show as a tag cloud on your plugin page, as long as other plugins exist that target them, so think carefully about the order you list your tags in too.
  • There should be an entry in the changelog section that matches the Stable tag value. Only keep changelog entries for the current major version, so if you're jumping from version 1.2.3 to 2.0.0 then move the existing entries into a separate changelog.txt to de-clutter the file, but if you're jumping from 1.2.3 to 1.2.4, or 1.3.0, then leave the existing entries in place.
  • There should be an entry in the screenshots section for each screenshot you add to the assets folder.

Finally, you can commit your changes to the SVN repository. To do this, first add all of the files that you've just added to your local plugin folder, into the commit queue via svn add commands, and then issue an svn ci command to "check in", or commit, your changes. Remember to replace the plugin name and username with your own details, and the version number to match the version you're actually submitting:

$ cd local-foo-bah-plugin
$ svn add assets/*
$ svn add trunk/*
$ svn ci -m 'Adding version 1.0.0' --username foo-bah-username

The live, public repository should now be updated with your new plugin files, but WordPress uses folders in the tags tree to manage actual releases, so you need to copy this release into that tree:

$ svn cp trunk tags/1.0.0
$ svn ci -m 'Tagging version 1.0.0' --username foo-bah-user

Your plugin page should update immediately, showing the assets you uploaded and the content of your readme file. Your plugin is now available in the WordPress repository for people to find and install, to review, and to request support. If your plugin really is named foo-bah-plugin then your support page will be at https://wordpress.org/support/plugin/foo-bah-plugin and you should log in to that and hit the subscribe link to be notified of requests.

Updating a WordPress plugin via SVN

Once your plugin is live, you'll inevitably need to update it. Again, WordPress uses the tags folder to manage releases so this process is basically the same as the latter half of the initial upload procedure.

First off, and especially if you're working in a team, you should check that your local copy is up to date because the SVN repository might have been changed since your last check out:

$ cd local-foo-bah-plugin
$ svn up

Now you can once again use your file browser or regular cp commands to copy any new or updated files in into your local plugin folder.

If you're adding new files, you'll also need to use svn add commands again, to tell Subversion that you want those files added to the commit queue. You can use svn stat and look for files in the output that are flagged with a question mark to determine which are currently unrecognised by Subversion. Alternatively, you can just use svn add --force trunk to add all new files within the trunk directory, but be careful that your local folder doesn't contain anything that you wouldn't want uploaded, like the .DS_Store files on a Mac.

If you want to delete any files, use svn rm commands which will both remove the local copy, and add a removal operation to the commit queue. Subversion is already monitoring files that it knows about for changes, so you don't need to run any special commands on those. Just new file additions and old file removals.

So for example, if you're adding two new files, deleting one old file, and making changes to another dozen, you just do this:

$ svn stat
$ svn add trunk/a-new-file.php
$ svn rm trunk/an-old-file.php
$ svn rm trunk/another-old-file.php

Or if you're adding tonnes of new files and you're absolutely certain there's nothing in there that you wouldn't want to commit:

$ svn add --force trunk

As before, make sure your readme file is up to date before committing:

  • Version bump the Stable tag value of your readme file, and the Version value of your main code file. Again, remember that version numbers should be x.y.z formatted, where x increments represent breaking changes, y increments represent new non-breaking features, and z increments represent minor changes or bug fixes.
  • Check that the Tested up to value matches the latest version of WordPress which you know that your plugin works with. Remember that this should be x.y formatted, not x.y.z.
  • Add an entry to the changelog section that matches the Stable tag value. Once again, only keep changelog entries for the current major version, so if you're jumping from version 1.2.3 to 2.0.0 then move the existing entries into a separate changelog.txt to de-clutter the file, but if you're jumping from 1.2.3 to 1.2.4, or 1.3.0, then leave the existing entries in place.
  • If you've added, removed, or replaced any screenshots, make sure the screenshots section is up to date too.

Now you're ready to commit, and create a new release in the tags folder:

$ svn ci -m 'Adding version 1.0.1' --username foo-bah-username
$ svn cp trunk tags/1.0.1
$ svn ci -m 'Tagging version 1.0.1' --username foo-bah-user

Updating a WordPress plugin page without submitting any plugin changes

WordPress plugin pages are based on the content of the readme file in your current stable release, i.e. the folder in the tags tree which matches the Stable tag value of your trunk folder readme file. So if you want to make changes to your plugin page but you're not actually updating the plugin itself, then all you need to do is commit a new readme file to trunk, and re-copy it to the relevant tags folder. WordPress allows you to make plugin page or aesthetic-only plugin changes without version bumping.

So, once again you should make sure that your local plugin folder is up to date:

$ cd local-foo-bah-plugin
$ svn up

Then make your changes to both your local trunk/readme.txt and your local tags/1.0.1/readme.txt for example, and when you're done, just commit:

$ svn ci -m 'Updating readme in trunk' --username foo-bah-username

And we're done!

Photo of Ric

Ric

Ric is a senior web and game programmer with nearly 30 years industry experience and countless programming languages in his skillset. He's worked for and with a number of design and development agencies, and is the proprietor of QWeb Ltd. Ric is also a Linux server technician and an advocate of free, open-source technologies. He can be found on Mastodon where he often posts about the projects he's working on both for and outside of QWeb Ltd, or you can follow and support his indie game project on Kofi. Ric also maintains our Github page of useful scripts.

Blog posts are written by individuals and do not necessarily depict the opinions or beliefs of QWeb Ltd or its current employees. Any information provided here might be biased or subjective, and might become out of date.

Discuss this post

Nobody has commented yet.

Leave a comment

Your email address is used to notify you of new comments to this thread, and also to pull your Gravatar image. Your name, email address, and message are stored as encrypted text. You won't be added to any mailing list, and your details won't be shared with any third party.

This site is protected by reCAPTCHA and the Google Privacy Policy & Terms of Service apply.