WordPress plugin changelogs: making readme.txt work for you
Every WordPress plugin ships its changelog in a file with a format frozen somewhere around 2010:
readme.txt, with its == Changelog == section and = 1.2.3 =
version headings. It is easy to treat as a packaging chore — one more file the directory makes
you fill in. That is a mistake, because the readme.txt changelog is displayed at the single most
consequential moment in your relationship with a user: when they are staring at the Updates screen
of a live site, deciding whether to press Update now. This guide covers how the
format actually works, where the text really shows up, the underused Upgrade Notice
section, and the habits that separate plugins people update promptly from plugins people are
afraid to touch.
Your reader is holding a live site
Most changelog readers are curious. WordPress changelog readers are nervous. The person reading yours is typically a site owner or freelancer looking at a wall of pending updates on a production site — often without a staging environment, sometimes without a recent backup. One bad plugin update can white-screen a business's storefront. So the question your changelog must answer is not "what's new?" but "is it safe to press the button?"
That reader rewards a very specific style: short dated entries, fixes described by symptom ("fixed a fatal error when WooCommerce is disabled"), clear flags on anything that changes behavior, and an explicit note when a release touches the database or settings. It is the same 30-second trust decision a dependabot reviewer makes on a bump PR — except this reviewer can't read your diff, so the changelog is all they have. Plugins whose changelogs consistently pass that test get updated promptly; plugins that write "bug fixes and tweaks" train users to defer updates, which is exactly how sites end up running versions with known vulnerabilities.
Where the text actually shows up
readme.txt is not really a README — it's structured metadata the wordpress.org directory parses. Your changelog section surfaces in three places:
- The "View version details" modal on the wp-admin Updates and Plugins screens — the changelog tab is front and center at decision time. This is the one that matters.
- Your plugin's directory page, under the Changelog tab — read by people evaluating the plugin before install (an active, specific changelog is social proof the plugin is maintained).
- Third-party tooling — management dashboards (MainWP, ManageWP) and security scanners surface it when queueing bulk updates across client sites.
Note what's not in that list: your website. Users deciding whether to update never see your blog post. Whatever you write elsewhere, the readme.txt slice is the copy that reaches them in-context.
The format, mechanically
The changelog lives in a == Changelog == section, with one = version =
subheading per release and Markdown-ish bullets under each. The parser is strict about the
heading syntax and forgiving about little else:
== Changelog == = 2.4.1 — 2026-07-20 = * Fix: fatal error on the settings screen when PHP 8.3 is used with object caching enabled * Fix: export button did nothing when the site URL contained a port number = 2.4.0 — 2026-07-08 = * New: bulk-edit support for redirect rules * Improved: import screen now shows a progress bar for files over 1 MB * Note: this release adds one database table (wp_myplugin_log); created automatically on update
Rules the format won't enforce but your readers will:
- Add dates yourself. The spec only asks for
= version =, and the directory shows no date — so a reader can't tell if the top entry shipped last week or in 2023. Put an ISO date in the heading, as above. - Newest first. The modal shows the section as-is; if 1.0 is at the top, that's what people read at update time.
- Version headings must match released versions — including the
Stable tagheader. If your stable tag says 2.4.1 and the changelog stops at 2.3, the modal shows stale text and readers assume the worst. - Prefix entries (Fix / New / Improved / Security / Note) so the nervous reader can scan for the two kinds that matter to them: Fix and anything scary.
- Run it through the readme validator — malformed headings silently collapse your changelog into a wall of text in the modal.
The full header/section reference is in the official How your readme.txt works doc.
Upgrade Notice: the best placement you're not using
readme.txt supports a second, almost universally ignored section:
== Upgrade Notice == = 2.4.0 = 2.4.0 adds a database table and changes the redirect-rule format. Back up before updating; rules are migrated automatically on first load.
The notice for versions between the user's installed copy and the new one can be shown directly on the update screen — no click into the modal required. It's limited to about 300 characters, which is the point: one sentence of triage. Use it only when a release deserves extra attention — a schema change, a settings migration, a security fix worth expediting, a minimum-PHP bump. If every release carries an urgent notice, you've reinvented notification inflation and readers will tune it out; an empty Upgrade Notice section for routine releases is the feature working as designed.
Trim the changelog; archive the history
readme.txt ships inside your plugin zip to every one of your installs, and the directory page renders the whole section. Ten years of history in readme.txt means megabyte-scale readmes, slower directory pages, and a changelog tab where the signal drowns. The convention that's emerged among well-run plugins:
- Keep the last 10–20 releases (or ~2 years) in readme.txt — enough for any plausible version jump.
- End the section with a pointer: "Earlier history: see changelog.txt" (a plain file in the zip) or better, a link to a hosted changelog page with permalinks, search, and a feed — which readme.txt will never have.
The hosted page also solves readme.txt's structural limits: no permalinks to a specific entry (you can't link "the 2.1.0 breaking change" in a support thread), no tags, no RSS for the agencies who manage 40 sites and want to subscribe to your changes rather than poll the directory. (Starting one for an existing plugin is a paste, not a project — more on that below.)
Security fixes: the ecosystem has rules
WordPress plugins are the most-attacked software distribution channel on the web, and attackers diff plugin releases within hours of them hitting the directory's public SVN. That changes the calculus:
- Never patch silently. "Misc hardening" with no Security entry doesn't slow attackers — they read diffs, not readmes. It only slows defenders, who use the changelog to prioritize which of 30 pending updates to apply first.
- Be precise about impact, vague about mechanism at ship time: "Security: fixed a vulnerability affecting sites with open registration; all users should update" — severity and affected configurations, no recipe. Pair it with an Upgrade Notice.
- Let the details come later via an advisory (a CVE through a CNA like Wordfence or WPScan, or a disclosure post) once updates have propagated — the two-documents-two-clocks pattern.
The directory's own guidance on handling reports is here; the communication side is the same as any hotfix: ship-day stub, edit-in-place later, same URL.
The compat headers are changelog, too
Three readme.txt headers — Tested up to, Requires at least,
Requires PHP — are trust signals with changelog semantics. "Tested up to: 6.3" on
the day 6.6 ships reads as abandonment, and the directory shows warnings for it. Bumping
Tested up to promptly after each core release (it needs only a readme change, not a
version bump) is the cheapest maintenance signal you can send. And when you raise
Requires PHP or drop a WordPress version, that's a breaking change for someone — it
belongs in the changelog as its own loud entry, announced a release ahead, exactly like
dropping a runtime in a library.
Anti-patterns that keep sites unpatched
- The eternal "Bug fixes and improvements." Costs you the only channel that reaches users at update time, and teaches them your updates aren't worth reading — or applying. The symptom-first rewrite exists for exactly this reader.
- Changelog lagging the stable tag. Shipping 2.4.1 with a changelog that stops at 2.3 makes the version-details modal actively misleading.
- Marketing in the changelog. "Check out our new Pro tier!" in the update modal reads as upsell at a moment of vulnerability, and the reviews section will tell you so.
- All history, forever, in readme.txt. Bloats every install and buries recent changes. Trim + archive.
- Silent security patches. Defenders deprioritize your update; attackers diff it anyway. Worst of both.
- Urgent Upgrade Notices on routine releases. The 300-char slot works because it's rare. Spend it like it costs money.
One canonical changelog, mirrored into readme.txt
The workable setup mirrors the app-store two-layer
pattern: a canonical hosted changelog — permalinks you can drop into support
threads, tags (fix / security / breaking), RSS for the agencies, search — and a
trimmed readme.txt slice generated from it at release time. Write once at ship
time; the readme fragment is a mechanical copy of the latest entries in = version =
format.
Wakelog is a good home for the canonical layer: import your existing readme.txt history in one
paste (the = 1.2.3 = heading style parses as versions), post from your release script
with one curl or wakelog post --from-git, tag entries fix /
security / announcement, and point support threads at stable permalinks.
Your users keep the readme.txt slice they expect; you get the archive, the feed, and the links
readme.txt can't give you.
Start your free changelog Next: open source changelogs →
Related guides
- Browser extension release notes: shipping updates users never asked for
Your update installs itself in a million browsers on a schedule you don’t control, and one bad permission prompt can end it. Where extension release notes live, and how to write the ones that keep trust. - Theme and template changelogs: shipping updates to products people copy
Every buyer owns a customized copy, so updates are hand-merges. Safe-to-overwrite verdicts, changed-file lists, the changelog tab as a sales page, and notes for buyers three versions behind. - Security advisories vs changelog: how to publish a security fix
A security fix needs two write-ups on two different clocks: the ship-day changelog entry and the full advisory. What goes in each, when a CVE is worth it, and why silent patching always backfires.
Last updated 2026-07-27 · All guides