Skip to content

V2 namespace: frozen legacy, config-array API, license notices (2.0.0) - #26

Merged
shazzad merged 9 commits into
mainfrom
feature/v2-namespace
Aug 19, 2026
Merged

shazzad merged 9 commits into
mainfrom
feature/v2-namespace

Conversation

@shazzad

@shazzad shazzad commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Implements the versioned-namespace design (spec: docs/superpowers/specs/2026-08-19-versioned-namespace-v2-design.md).

What's in

  • src/V2/ — behavior-identical port of the library under Shazzad\PluginUpdater\V2: Integration (config-array constructor), License\Store (all storage-key/migration/status logic split out, byte-identical key behavior), Client, Updater, Tracker, Admin\LicensePage. Legacy src/ untouched and frozen (critical fixes only).
  • Config surface — keys api_url, file (__FILE__ or basename form), product_uid, product_id, license, menu, meta, meta_callback; unknown keys, missing required keys, non-callable meta_callback, and uid-without-id all fire _doing_it_wrong() (debug-visible, never fatal).
  • License visibility (new features) — Admin\Notices: dismissible admin notices for unlicensed ("enter your license key") and expired ("renew") states, update_plugins capability, one-week nonce-protected site-wide snooze per product per type. Admin\UpdateMessage: non-dismissible in_plugin_update_message row line explaining the disabled update. Both auto-wired when licensing is enabled; free mode gets neither.
  • Review fixes — four confirmed findings from the high-effort review: uid-without-id migration warning, plugin_basename() normalization, V1-compatible menu falsy semantics, is_callable() for meta_callback in pings.

Tests

tests/V2/ ports all 8 legacy files plus new coverage for the constructor, notices, snooze lifecycle, and update-row message. Suite: 208 tests / 386 assertions, green (legacy tests byte-identical; the 6 risky no-assertion tests pre-exist on main). PHPCompatibility 7.4- clean.

After merge

Manual test round on the SPU test plugin (already switched to V2, live on the w4dev dev stack), then tag 2.0.0 (no v prefix). First adopter: LoxoWP, proving licenses survive V1→V2 untouched.

🤖 Generated with Claude Code

https://claude.ai/code/session_013qm7gJnmWsXnL3uZwwXVLj

shazzad and others added 9 commits August 19, 2026 13:52
Behavior-identical port of the five legacy classes: Integration gains the
config-array constructor with product_uid as primary identity; license/option
storage moves to License\Store with identical wp_options, transient and cron
keys; Admin becomes Admin\LicensePage. Legacy src/ is untouched and frozen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All 8 legacy test files adapted to the V2 namespace and config-array
construction (fixtures and legacy tests untouched), plus a V2-only
IntegrationConfigTest for the new constructor surface: uid via config,
construction-time legacy migration, and menu defaults. Integration's
subsystem properties stay untyped like legacy — they are the seam the
Tracker tests (and consumers) use to swap stand-ins.

Full suite: 179 tests / 322 assertions green on PHP 8.3.11.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tices

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sites without a license key get a dismissible 'enter your license key'
admin notice; expired licenses get a renew notice with the renewal URL,
shown whether or not an update is pending. Dismissal snoozes that
product's notice type site-wide for one week via a nonce-checked
admin_init handler. The plugins-list update row additionally explains
the empty package inline (non-dismissible by design). Both instantiate
only when licensing is enabled, so free-mode plugins are untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n, menu falsy semantics, callable meta

- warn via _doing_it_wrong when license+product_uid come without product_id
  (V1-ported plugins would silently change storage/cron identity)
- normalize the file config key through plugin_basename() so __FILE__ and
  basename form both work; spec example is now correct
- a falsy non-array menu value hides the license page again (V1 truthiness);
  arrays and an absent key show it
- Client::ping() invokes any callable meta_callback (was Closure-only, dropping
  the string callable the spec example shows); meta values resolve Closures and
  array-callables but keep plain strings as data; non-callable meta_callback
  config fires a validation notice

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ode only

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@shazzad
shazzad merged commit 740bcb4 into main Aug 19, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant