Submitting a plugin to the WordPress.org directory is a two stage process: you upload a zip through the developer portal and wait for a human review, then, once approved, you get a Subversion repository and every release from that point onward is an SVN commit rather than an upload. Most first submissions are rejected for the same handful of reasons, and almost all of them are fixable before you ever click submit.
readme.txt with a unique plugin name, GPL compatible license, and a Stable tag that is a real version number, zip the plugin folder, and upload it at wordpress.org/plugins/developers/add/. After the plugins team approves it you receive an SVN URL, then svn co the repo, put your code in trunk/, images in assets/, run svn cp trunk tags/1.0.0, and commit. The directory serves whatever version the stable tag in trunk/readme.txt points at.This guide assumes you already have a working plugin. If you do not, start with our beginner tutorial on creating a WordPress plugin, or read building a WordPress plugin from scratch if you are structuring something larger with Composer and tests. The steps below reflect the directory as it works in 2026, on the current WordPress 7.1 line.
The pre submission checklist
Reviewers work through a consistent list. Going through it yourself first is the difference between a one round approval and three weeks of back and forth.
Every function, class, constant, option, and database table your plugin creates needs a unique prefix. Generic names such as get_options() or a table called wp_settings are an automatic rejection because they collide with other plugins. Sanitize every input, escape every output, and check a capability plus a nonce before any action that changes state. Do not load JavaScript or CSS from a CDN; bundle it. Do not phone home to your own server without asking, and if your plugin does call an external service, document exactly what it sends and link that service’s terms and privacy policy from your readme.
Strip the development scaffolding out of the zip. Node modules, the .git directory, PHPUnit fixtures, and Composer development dependencies all bloat the package and give reviewers more surface to question. A production zip should contain the plugin and nothing else.
readme.txt, the file that decides your listing page
The readme.txt is parsed to build your public page, so getting it wrong produces a broken listing even after approval. It uses a WordPress specific flavor of Markdown, not standard Markdown.
=== GB Reading Time ===
Contributors: ethancaldwell
Tags: reading time, blocks, shortcode
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Adds an estimated reading time to posts as a block and a shortcode.
== Description ==
Longer prose here. This section supports headings, lists and links.
== Installation ==
1. Upload the plugin folder to `/wp-content/plugins/`.
2. Activate it through the Plugins screen.
== Frequently Asked Questions ==
= Does it work in a block theme? =
Yes, the block can be placed in any template.
== Screenshots ==
1. The block in the editor.
== Changelog ==
= 1.0.0 =
* First release.
== Upgrade Notice ==
= 1.0.0 =
First release.Three header fields cause most of the trouble. Tags is limited to five terms and reviewers reject competitor names used as tags. Tested up to takes a WordPress version number only, and letting it fall more than a couple of releases behind puts a warning on your listing. Stable tag is covered in its own section below because it deserves one.
The review queue and what to expect
You upload the zip at the developer portal, receive an automated email, and then wait. The plugins team runs an automated scan first, and a human reads the code afterward. The wait has varied a great deal over the years: the team reported a backlog of roughly a thousand plugins in the spring of 2026 and then reported clearing it to near zero by June, with submissions running around several hundred per week. Treat the current wait as days to a few weeks rather than a fixed number, and check the plugins team blog if the timeline matters to your launch.
When a reviewer finds a problem you get an email listing every issue at once. Fix them all, reply to the same email thread with a new zip attached or a link to it, and the clock does not restart from zero. Replying with only half the fixes is what turns a single round into four.
readme.txt at submission time and cannot be changed afterward without resubmitting as a new plugin. Choose it as carefully as a domain name. Slugs that begin with another company’s trademark are rejected.The SVN workflow
Approval gives you a repository at https://plugins.svn.wordpress.org/your-plugin-slug with three directories. Subversion here is a deployment mechanism, not a place to develop; keep your day to day work in Git and push releases across.
| Directory | Contains | Shipped to users? |
|---|---|---|
trunk/ | Current development code and the authoritative readme.txt | Only if the stable tag says trunk |
tags/ | One frozen folder per released version | Yes, the one matching the stable tag |
assets/ | Banner, icon, screenshots | No, used for the listing page only |
branches/ | Optional long lived work | No |
svn co https://plugins.svn.wordpress.org/gb-reading-time gb-svn
cd gb-svn
rsync -a --delete \
--exclude '.git' --exclude 'node_modules' --exclude 'tests' \
~/code/gb-reading-time/ trunk/
svn add trunk/* --force
svn ci -m "Release 1.0.0" --username ethancaldwell
svn cp trunk tags/1.0.0
svn ci -m "Tagging version 1.0.0"Never develop inside a tag directory. Tags are meant to be immutable snapshots, and editing one after release means some sites have a different 1.0.0 than others. If you shipped a broken release, bump the version and tag again rather than rewriting history.
# Removing files that no longer exist in your build
svn status | grep '^!' | awk '{print $2}' | xargs -r svn rmBanners, icons, and screenshots
Assets live in the top level assets/ directory, never inside trunk/. File names are fixed and must be lowercase.
| Asset | File name | Pixels |
|---|---|---|
| Banner, standard | banner-772x250.png | 772 by 250 |
| Banner, high density | banner-1544x500.png | 1544 by 500 |
| Icon, standard | icon-128x128.png | 128 by 128 |
| Icon, high density | icon-256x256.png | 256 by 256 |
| Screenshots | screenshot-1.png and up | Any, captioned in readme.txt in order |
An icon.svg is accepted but still needs a PNG fallback. Screenshot captions come from the numbered list under the == Screenshots == heading in readme.txt, matched by position, so a missing caption shifts every image after it.
The stable tag trap
This is the single most misunderstood part of the directory. WordPress reads Stable tag from trunk/readme.txt, and only from there. It then serves the plugin from tags/<that value>/. Three failure modes follow from that.
If you tag 1.1.0 but forget to update the stable tag in trunk/readme.txt, users keep getting 1.0.0 forever and your update never ships. If you set the stable tag to a version you never tagged, the download breaks entirely. And if you set it to trunk, every commit to trunk is instantly live for every user, which the documentation actively discourages for new plugins because there is no way to roll back.
Stable tag in trunk/readme.txt, add the changelog entry, commit trunk, then svn cp trunk tags/x.y.z and commit again. Updating the readme in trunk after tagging still works, because trunk is where the stable tag is read from.Troubleshooting
Your update does not appear on the listing. The directory syncs on a schedule rather than instantly. Wait fifteen minutes, then verify that tags/x.y.z/ exists and that trunk/readme.txt names exactly that version, with no leading v and no trailing whitespace.
svn: E170013 or an authentication failure. Usernames are case sensitive and are your WordPress.org login, not your email. If you use two factor authentication, generate an application password in your WordPress.org profile and use that instead of your account password.
The readme parser shows an empty description. The section headings must be exactly == Description == with two equals signs and surrounding spaces, and the short description directly under the header block must be a single paragraph under about 150 characters. Check your file against the official readme validator before committing.
Reviewers say your plugin loads remote code. Something in the zip fetches a script or stylesheet from a CDN, or a bundled library calls out on load. Self host everything except genuine third party service integrations, and remove any vendored library you are not actually using.
The banner is not showing. Assets committed inside trunk/assets/ are ignored. They belong in the repository root assets/ directory, at the same level as trunk and tags.
Frequently asked questions
How long does approval actually take?
It varies with the queue depth and the complexity of your code. The plugins team publishes status updates, and through 2026 the queue moved from a backlog of about a thousand plugins down to near zero. Plan for days to a few weeks, and do not schedule a launch announcement around an unconfirmed date.
Can I use Git instead of Subversion?
You can develop in Git and script the release into SVN, which is what most maintainers do. There is no official Git remote for the plugin directory. A short deploy script or a GitHub Actions workflow that copies your build output into trunk and tags it removes almost all of the friction.
What license do I have to use?
GPLv2 or later, or a license compatible with it, and that applies to every asset in the package including images and bundled libraries. Declare it in both the plugin header and readme.txt. A bundled font or icon set under a noncommercial license will fail review.
Can I sell a directory hosted plugin?
Not the hosted version itself, and it cannot be crippled to push an upgrade. What you can do is offer a separate commercial product, mention it in the readme, and keep the free plugin fully functional on its own. Our guide on how to sell WordPress plugins covers the commercial side.
What happens if I stop maintaining it?
The listing stays up with a notice that the plugin has not been updated against recent WordPress releases. You can close it yourself from the developer tools on your plugin page. If it has a known unpatched vulnerability, the team can close it for you and remove it from search.
The bottom line
The directory is not hard to publish to; it is unforgiving about details. Unique prefixes, a GPL compatible license, escaped output, and a stable tag that points at a tag which actually exists will get you through the first review and every release after it.
Read the detailed plugin guidelines once end to end before submitting, and keep the Subversion reference open during your first release. If you want a finished project to submit, how to make a WordPress plugin that does something useful builds one end to end.
