WP Sudo follows Semantic Versioning 2.0.0. Semver is only meaningful once "the public API" is defined, so this document does that first, then states the bump rules and how they map to our commit conventions.
This file is the canonical source for how a version number is chosen.
docs/release-status.md remains the source for current release state, and the
version-sync checklist in CLAUDE.md remains the mechanical release procedure.
A version bump is judged against this declared surface β the contracts external
code (themes, other plugins, site glue code, WP-CLI users, integrations) can
depend on. The canonical, signature-level list lives in
docs/developer-reference.md; this is the summary
of what is covered:
- Global functions β
wp_sudo(),wp_sudo_check(),wp_sudo_require(),wp_sudo_can(),wp_sudo_governance_caps(),wp_sudo_map_governance_meta_cap(),wp_sudo_is_recovery_mode(),wp_sudo_build_challenge_url(). - Filters β e.g.
wp_sudo_gated_actions,wp_sudo_guard_escalation,wp_sudo_allow_escalation,wp_sudo_cookie_secure,wp_sudo_grant_session_on_login,wp_sudo_requires_two_factor,wp_sudo_two_factor_window,wp_sudo_validate_two_factor,wp_sudo_log_passed_events_enabled,wp_sudo_wpgraphql_bypass,wp_sudo_wpgraphql_classification. - Action (audit) hooks β the documented
wp_sudo_*do_actionhooks and their argument signatures (session lifecycle, gated actions, policy presets, escalation blocks, session revocation, tamper detection, etc.). - The gated-rule structure β the array shape a
wp_sudo_gated_actionscallback receives and returns (ruleid, matcher keys, category, etc.). - Documented class API used by integrations β the
Sudo_Sessionmethods and constants documented in the developer reference (is_active(),is_within_grace(),activate(),deactivate(),GRACE_SECONDS). - WP-CLI commands β the
wp sudocommand names, arguments, and output contract. - The
sudo_requiredsoft-block payload β the documented error code/shape returned to AJAX/REST clients. - Public constants β
WP_SUDO_VERSION,WP_SUDO_RECOVERY_MODE, and other documentedWP_SUDO_*constants. - The settings option contract β the
wp_sudo_settingsoption keys that are documented as stable. - Slug and text domain β
wp-sudo(changing either is a breaking change).
Changes confined to the following are not API changes and do not, on their own, warrant a MINOR or MAJOR bump:
- Internal classes and private/protected methods β anything not documented in
the developer reference (e.g.
Gateinternals,Challenge,Request_Stash,Adminrendering helpers, theUser_Identitydisplay helper). - Admin-UI presentation β markup, CSS, labels, layout, and wording of the settings pages, dashboard widget, Access tab, and challenge page.
- Database table internals β column layout of the events table and other internal storage, except where a documented contract depends on it.
- Test code, tooling, CI, and documentation.
- Undocumented hooks/behavior β if it is not in the developer reference, callers should not depend on it, and we do not treat it as covered.
Given the surface above:
- MAJOR (
X.0.0) β a backward-incompatible change to the declared public API: removing/renaming a function, filter, hook, CLI command, or constant; changing a documented signature or the meaning of a return value; changing the gated-rule structure incompatibly; raising the minimum WordPress/PHP requirement; changing the slug or text domain. - MINOR (
x.Y.0) β a backward-compatible addition to the declared public API: a new filter/hook/function/CLI command/constant, a new documented setting, a new optional parameter, or a new gated surface consumers can rely on. - PATCH (
x.y.Z) β a backward-compatible bug fix, security fix, internal refactor, or admin-UI/UX change that touches no declared public API.
- 4.5.1 (PATCH) β PR #154 harmonized the dashboard-widget and Access-tab user
presentation and fixed a
get_avatar()forceβforce_displayno-op. It added an internalUser_Identityhelper and changed admin markup/CSS only β no public hook, filter, function, or documented contract. Admin-UI change + bug fix β patch, even though it is user-visible. (Visible β minor; the API contract, not the pixels, decides.) - 4.6.0 (MINOR) β this release was re-scoped up from a staged
4.5.1. The headline is a user-visible new capability β block-editor in-editor reauthentication (asudo_requiredsnackbar link-out plus a logged-in-onlyadmin-ajaxnonce-refresh endpoint). That capability, taken alone, adds no new declared public-API entry (it is admin JS + an internalChallengeendpoint), so by the4.5.1rule above it would be patch-level β visible β minor. What sets the floor at minor is that the same release shipped the optional Critical-Event Alert Bridge (#166), which adds new documented public extension points βwp_sudo_critical_alert_events,wp_sudo_critical_alert_recipient,wp_sudo_critical_alert_throttle,wp_sudo_critical_alert_hourly_cap,wp_sudo_critical_alert_dispatch(filters) andwp_sudo_critical_alert_dispatched(action), all documented in the developer reference. Documented extension points shipped in the product count toward the public API even when they live in an optionalbridges/mu-plugin (that file carries its own@versionfor its internal iteration, but adding brand-new documented hooks to what WP Sudo ships is a backward-compatible API addition). New documented filters/action β MINOR. Lesson: bump for the declared-API addition, not merely because a feature is visible β the visible editor feature is the headline, the bridge hooks are the contract reason. - 4.7.0 (MINOR, maintainer override) β a deliberate exception to the rule above.
The 4.7.0 payload completes the in-editor reauthentication modal that 4.6.0
explicitly deferred: the in-place password modal with request re-dispatch
(Milestone A) and the in-modal second factor (Milestone B). By the strict test
this would be patch-level β it is block-editor JS plus a new internal
ChallengeAJAX endpoint (wp_sudo_challenge_2fa_partial), and it fires the pre-existing, already-documentedwp_sudo_render_two_factor_fieldsaction (indocs/developer-reference.md; a bridge-facing integration hook that predates this release) from a new context β the in-modal AJAX partial. No new entry was added todocs/developer-reference.md, and no new symbol joins the declared public API. It was nonetheless released as MINOR as a maintainer product-signaling decision: finishing a headline, previously-deferred capability warranted a minor rather than burying it in a patch. This is recorded here explicitly so the choice reads as an intentional override, not versioning drift β the default rule stands (visible β minor; a completed internal-only feature is patch), and future releases should not treat "it's a big visible feature" as minor-qualifying on its own without a declared-API addition. - A new
wp_sudo_*filter orwp sudosubcommand β MINOR. - Removing
sudo_can()in favor ofwp_sudo_can()(4.0.0) β MAJOR.
This repository uses Conventional Commits.
Automated version tools map feat: β MINOR and fix: β PATCH, so commit type
must reflect the public-API rule above, not merely whether something is
user-facing:
- Reserve
feat:for additions to the declared public API (a new filter/hook/function/CLI command/setting/gated surface). - Use
fix:,refactor:,style:, orperf:for bug fixes, internal changes, and admin-UI/UX work that adds no public API β these are PATCH-level. - Use a
BREAKING CHANGE:footer (or!) only for a backward-incompatible change to the declared API β MAJOR.
Rule of thumb: if you cannot point to a new entry this change adds to
docs/developer-reference.md, it is not a feat:.
- Releases are annotated tags
vX.Y.Zcut from the release commit; the GitHub Release is published from that tag. Tagging/publishing is maintainer-owned. - Every release keeps the five version-sync points in agreement (see the
CLAUDE.mdversion-sync checklist). This is a manual release-checklist step βverify:metricschecksdocs/current-metrics.md(test/LOC/registry counts), not the version-sync points, so version-sync drift is caught by the checklist, not by an automated CI gate. - The public "Try latest release" Playground badge loads
blueprint.jsonfrommain, so its tag-ZIP target is bumped after the tag is cut, never before (a pre-tag bump would make the public demo fetch a missing ZIP).
Not applicable β WP Sudo is past 1.0, so the rules above apply in full. (For any future 0.x companion repo, note that under semver 0.x a MINOR may carry breaking changes; such a repo needs its own stated stance.)