Repository navigation
V3: Insights (consent-based usage tracking) + commercial V3 Integration - #29
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
V3\Insights wires Consent, Collector, Client, Scheduler and the opt-in Notice for free plugins. Nothing is sent before an admin allows it: Client::track() and Client::optout() refuse without consent, so every call path shares one gate. The parts take plain constructor args so the commercial V3\Integration can build them with consent pre-granted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Covers config validation, payload shape and the 200-plugin cap, meta and license resolution, the consent state machine, notice gating, the Allow / No thanks handler, the no-HTTP-before-consent rule on every path, opt-out, and a static guard that the free files never reach update or license code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copies the V2 commercial entry point (Integration, Client, Updater, Tracker, License/Store, Admin/*) into the V3 namespace with identical storage keys, transients, cron hook and admin behaviour, so a plugin moving V2 -> V3 keeps every saved license. Differences from V2: - Integration builds the Insights parts in commercial mode (consent implied, never asked, no Notice) and exposes them as insights_consent / insights_collector / insights_client / insights_scheduler. New optional insights_api_url config key; by default derived from api_url (/wp-repo/v3 -> /wp-repo-insights/v1). An underivable api_url fires _doing_it_wrong and leaves Insights off. - The license key rides in the Insights payload when licensing is on. - Client::ping() is gone; the hourly license sync only checks the license, activation/deactivation/upgrade only refresh caches and leave tracking to the Insights scheduler (no double send). - admin_email/admin_name leave Integration (the collector reads them); meta/meta_callback and setMeta()/setMetaCallback() feed the collector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Carries the V2 Integration/Client/Updater/Tracker/Notices/UpdateMessage tests over to V3 (ping cases dropped) on a new IntegrationTestCase, and adds IntegrationInsightsTest (URL derivation, underivable api_url, commercial consent, license in payload, hourly sync never pings, exactly one activate/deactivate track, meta wiring, and a separate-process check that the commercial path never loads Insights\Notice) plus CommercialIsolationTest, a static guard over the commercial V3 files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README: Which namespace gains V3 (free V3\Insights + commercial V3\Integration), quick starts for both, V3 config tables, the Insights endpoints, and a "Shipping a free wp.org plugin" section with a tested strip + dump-autoload recipe. CLAUDE.md: V3 is active, V2 stable (additive fixes only), V3 architecture and isolation tests. CHANGELOG: 3.0.0 (unreleased). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A commercial plugin updated in place V2 -> V3 (WP-CLI, auto-update, MainWP) on a site where nobody opens wp-admin never got the daily Insights cron: only activation, admin_init and opt_in schedule it. No track was ever sent and the server marked the install inactive after 7 days. Tracker::sync_license_data() runs hourly from a cron Updater schedules on every init, so it now self-heals the daily event and calls run_daily(), whose 20h MIN_INTERVAL guard prevents double sends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The "What we collect" list under-disclosed what Collector::collect()
sends. It now covers every payload group: site name/URL/language plus the
multisite and local-site flags; WordPress version, memory limit and debug
mode; the active theme (name, version, parent); server versions and PHP
limits; user counts by role; active plugins' names and versions.
The admin line said "Your name and email address", but the payload carries
the site's admin_email option and the first administrator's display name,
not the clicking user: now "Your site's admin email address and
administrator name".
"Usage statistics specific to {name}" is added when meta or meta_callback
is configured, and a new notice.items config key appends extra lines
(non-empty strings; anything else is dropped with _doing_it_wrong()).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Insights::opt_out() set consent to "no" and dropped the deletion request
even when Client::optout() failed (timeout, 5xx); the client then refused
to send it later because consent was no longer granted.
A failed optout is now stored in {slug}_insights_optout_pending (first
failure and latest attempt) and retried on admin_init (at most hourly, so
a down server cannot slow every admin page) and by the daily cron, which
is kept for that. While pending, Client::optout() may send even though
consent is "no" -- it only ever sends {site_url, token}; tracks stay
refused. The flag clears on success, on a missing token, on a new opt-in
(which supersedes the deletion) or 7 days after the first failure.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Insights::uninstall( $file ) deletes the {slug}_insights_consent, _token,
_last_send and _optout_pending options and clears the
wprepo_insights_track_{slug} cron -- on every site of a multisite network
(get_sites + switch_to_blog). It sends nothing. Plugin authors call it from
uninstall.php (WP_UNINSTALL_PLUGIN) or a register_uninstall_hook callback.
A network deactivation now clears the daily cron on every site (the
deactivate hook's $network_wide argument); only the current site sends the
deactivate track, so a large network does not stall on N requests.
Both live in the free-safe files (Insights.php, Insights/Scheduler.php).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README: the V2 -> V3 migration note now lists what changed for callers -- Client::ping() and the public $admin_email / $admin_name are gone, and assigning $integration->meta / ->meta_callback after construction does not reach the payload (use setMeta() / setMetaCallback()). Also documents the full disclosure list, notice.items, the _optout_pending option, Insights::uninstall() with uninstall.php / register_uninstall_hook examples, and the hourly backup of the daily track. Spec: consent-notice section rewritten to the new list and wording; opt-out retry, uninstall, network deactivation and the hourly backup recorded. CHANGELOG: one line per review fix under 3.0.0. QA sheet: 443 tests, new notice wording, uninstall and hourly-backup checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Review fixes pushed (5 commits,
E2E: 22 passed, 2 failed, both on the server side. The shared local 🤖 Generated with Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server now serves the whole API plus Insights under wp-repo/v4, so V3\Integration drops insights_api_url and the /wp-repo/v3 -> /wp-repo-insights/v1 derivation and passes its api_url straight to the Insights client. V3\Insights takes the same v4 base. An api_url still on wp-repo/v3 draws a _doing_it_wrong() notice in both entry points, since v3 has no Insights routes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v3 has no Insights routes, so tracking there would 404 every day. The notice now says tracking is off; updates and licensing are unaffected. Also fixes CLAUDE.md, which still described insights_api_url. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shazzad
marked this pull request as ready for review
September 26, 2026 20:53
1 of 2 tasks
shazzad
added a commit
that referenced
this pull request
Sep 26, 2026
Revert V3 Insights merge (#29) for now
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What V3 is
A new
Shazzad\PluginUpdater\V3namespace (src/V3/) that adds Insights: usage tracking on our own repo server, replacing what Appsero does for us today. Design:docs/superpowers/specs/2026-09-26-v3-insights-design.md, plan:docs/superpowers/plans/2026-09-26-v3-insights-plan.md.It has two entry points:
V3\Insights. An Appsero-style consent notice (Allow / No thanks, nonce'd,manage_options). Nothing is sent until an admin clicks Allow. After that it sends a daily track plusactivate/deactivate/upgrade/optinevents towp-repo/v4/products/{key}/track, andopt_out()asks the server to delete the site's data. It loads no update or license code. Free plugins ship onlysrc/V3/Insights.php+src/V3/Insights/. The README has a tested build strip recipe.V3\Integration. This is the V2 entry point copied over, with the same config, option keys, transients, cron hookwprepo_sync_license_data_{name}, license page, notices and update-row message. A plugin moving V2 → V3 keeps every saved license. Tracking goes through the Insights parts in commercial mode: there is no consent step and no notice, and the license key is included. They are exposed as$insights_consent,$insights_collector,$insights_clientand$insights_scheduler.Client::ping()is gone. The hourly sync now only checks the license, and activate / deactivate / upgrade send exactly one Insights track.api_urlis the plugin-repowp-repo/v4base, which serves updates, licensing and Insights (one URL, no derived Insights URL). Anapi_urlstill onwp-repo/v3draws a_doing_it_wrong()notice and leaves tracking off; updates and licensing keep working.Isolation guarantees
mainand to the 2.1.1 tag. Plugins that stay on them see no change:tests/V3/InsightsIsolationTest.phpchecks that the free files never referenceUpdater,License*,Admin\*,Integration,Trackeror V1/V2.tests/V3/CommercialIsolationTest.phpchecks that the commercial V3 files never referenceInsights\Noticeor the free entry point, neverping, and never V1/V2.V3\Integrationand sending a track never loadsInsights\NoticeorV3\Insights. I made this test fail on purpose once, to confirm it can fail.Server dependency
This needs shazzad/plugin-repo 2.8.0 (#79:
wp-repo/v4= all of v3 +track/optout) deployed on w4dev.com before any plugin ships on V3 — before that, v4 has no update, license or Insights routes there.How to test
tests/V3/. The 9 "risky" warnings (no assertions: Mockery-only migration tests) already existed in V1/V2; the V3 copies inherit the same 3.docs/testing/v3-insights-manual-qa.md.Not released
This is a draft. There is no version bump beyond the CHANGELOG
3.0.0 - Unreleasedentry, no tag and no release.composer.jsonstates no version.🤖 Generated with Claude Code
Revised 2026-09-27: moved from the side namespace
wp-repo-insights/v1towp-repo/v4;insights_api_urlremoved.