Versioning in WordPress Plugins and Themes

·

WordPress has its own versioning convention that differs from strict Semantic Versioning (SemVer). If you’re building plugins or themes, especially ones others will extend, understanding this distinction is critical to avoid breaking your users’ sites silently.

The WordPress Versioning Model

WordPress itself uses a MAJOR.MINOR pattern for releases (6.4, 6.5, 6.6…), with patch releases added as a third segment only for security or critical fixes (6.5.3, 6.5.4…). Your plugins and themes should follow the same logic.

The general pattern is: N.N[.N[.N]]

Version Levels Explained

Major version: N.0

Use when the codebase undergoes a significant structural change: full rewrite, architectural overhaul, database schema redesign, or a change in core concept that makes the plugin fundamentally different from its previous version.

This is the nuclear option. Use it sparingly.

Examples:

  • Rewriting a plugin from a procedural approach to OOP with namespaces.
  • Migrating from custom meta storage to a CPT-based structure.
  • Dropping support for a major WordPress or PHP version (e.g., dropping PHP 7.x entirely).
  • Complete UI rebuild with a new settings API.

Key signal: If a user upgrades and needs to reconfigure, migrate data, or update their custom code to keep working, it’s probably a major version.

Minor version: N.N

Use when adding new functionality, or when a change is backward-compatible in terms of behavior but may affect code that extends your plugin via hooks, filters, or public functions.

This is where most of the active development lands.

Examples:

  • Adding a new settings page or admin section.
  • Introducing new hooks (do_action, apply_filters) or modifying existing hook signatures.
  • Adding a new public function or class to the plugin’s API.
  • Extending REST API endpoints or adding new ones.
  • Adding support for new block types or block variations.
  • Introducing new shortcodes or removing deprecated ones.
  • Adding or removing a dependency.

Key signal: If you changed or added anything in your plugin’s public contract (what third-party developers can hook into, call, or rely on) it’s a minor version bump.

Note on hook changes: Renaming a hook, changing its parameter order, or changing the data type of passed arguments is a breaking change. Even if you keep the old hook as a deprecated alias, bump the minor version and document it explicitly.

Patch version: N.N.N

Use for improvements, non-breaking fixes, performance improvements, or refactoring that doesn’t change behavior or public API.

Examples:

  • Fixing a bug in internal logic that wasn’t visible to end users.
  • Improving query performance.
  • Fixing a CSS issue in the admin UI.
  • Correcting a translation string.
  • Adding or improving inline documentation (docblocks).
  • Fixing a compatibility issue with a specific theme or plugin (without changing your API).
  • Updating a bundled library to a non-security patch version.

Key signal: A developer using your plugin can upgrade without reading the changelog and nothing will break.

Security patch: N.N.N.N

Use exclusively for security fixes or critical functional corrections that need to ship fast, in isolation, with zero other changes. The fourth segment exists to communicate clearly: this update is urgent and surgical.

Examples:

  • Fixing a SQL injection or XSS vulnerability.
  • Patching an IDOR (Insecure Direct Object Reference) in a REST endpoint.
  • Fixing a privilege escalation bug.
  • Correcting a data exposure issue (e.g., private post content leaking via API).
  • A broken function that causes data loss or corruption in a specific edge case.

Key signal: You want site owners and security scanners to be able to identify this as a security-specific release without reading the full diff. Keep it clean, no feature additions, no refactoring.

If you’re submitting to the WordPress.org plugin repository, security releases should also be accompanied by a note in the readme.txt changelog and a message to the Plugin Security Team if it’s a significant vulnerability.

Practical Rules

Start at 1.0.0, not 0.x

Some developers start plugins at 0.1.0 to signal «not production ready.» In the WordPress ecosystem, this is uncommon and confusing. If you’re releasing publicly, start at 1.0.0. If you’re in active development and not ready for production, don’t release publicly yet.

Never skip version levels downward

If your current version is 2.3.1 and you add a new feature, the next version is 2.4.0, not 2.3.2. It sounds obvious, but it’s a common mistake when teams are moving fast.

Keep readme.txt and plugin header in sync

The version declared in the plugin file header (Version: X.Y.Z) and the Stable tag in readme.txt must match exactly. Mismatches confuse WordPress.org, automatic updates, and any tooling that reads plugin metadata.

/**
 * Plugin Name: My Plugin
 * Version:     2.4.0
 */
Stable tag: 2.4.0

Document deprecations before removal

If you’re removing a function or hook in the next major version, mark it deprecated in the current minor version first. Use _deprecated_function() or _deprecated_hook() and give developers at least one minor release cycle to adapt.

function my_plugin_old_function() {
    _deprecated_function( __FUNCTION__, '2.3.0', 'my_plugin_new_function' );
    return my_plugin_new_function();
}

Version your database schema

If your plugin uses custom tables or stores a schema version in wp_options, track it separately and bump it explicitly when the schema changes. This is independent of the plugin version and controls upgrade routines.

define( 'MY_PLUGIN_DB_VERSION', '1.2' );

Tag releases in your VCS

Every public release should be a tagged commit (git tag v2.4.0). This gives you a clean diff between any two versions and makes it trivial to backport security fixes.

Quick Reference

Change typeVersion bumpExample
Full rewrite / major structural changeN.0.02.0.0
New feature / new or modified hookN.N.02.4.0
Bug fix / performance / internal refactorN.N.N2.4.1
Security fix / critical targeted correctionN.N.N.N2.4.1.1

A Note on Themes

The same logic applies to themes, with one additional consideration: themes are often extended by child themes. Any change to template file structure, template hooks (via get_template_part), or CSS custom properties that child themes rely on is effectively a public API change and warrants a minor bump, even if no PHP function changed.

Comments

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *