Skip to content

Resolve ping details at ping time rather than relying on init - #21

Merged
shazzad merged 2 commits into
mainfrom
fix/ping-resolves-own-product-data
Aug 5, 2026
Merged

shazzad merged 2 commits into
mainfrom
fix/ping-resolves-own-product-data

Conversation

@shazzad

@shazzad shazzad commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Summary

admin_email and admin_name are resolved in Updater::init(), hooked to init. The request that activates a plugin includes the plugin file and fires activate_{file} after init has already passed — so the add_action( 'init', … ) registered in the constructor during that include is too late to ever run, and Tracker::product_activated() pings with the constructor defaults of ''.

Observed in the wild, two pings six seconds apart from the same site:

11:44:21  POST /ping   product_status: inactive   admin_email: "eli@hudsoncreativestudio.com"
11:44:27  GET  /updates?license=…
11:44:27  POST /ping   product_status: active     admin_email: ""

Deactivation is unaffected — the plugin loaded normally at plugins_loaded in that request, so init ran.

product_version survives only by accident: product_activated() calls clear_updates_transient() before pinging, which sets the update_plugins transient, fires pre_set_site_transient_update_plugins, and backfills the version from $transient->checked[…] (Updater.php:106). That middle updates request is that path firing. The admin fields have no equivalent fallback.

Change

  • Integration::prepare_product_data( $force = false ) resolves version, name, admin email and admin name. Without $force it fills only what is missing, so the normal ping path costs a few empty() checks and nothing more.
  • Updater::init() delegates to it with $force = true — byte-for-byte today's behaviour on the init path.
  • Client::ping() calls it, so a ping is self-sufficient whatever the hook timing.
  • The wp-admin/includes/plugin.php include is now guarded by function_exists( 'get_plugin_data' ) instead of running unconditionally.

shazzad-plugin-repo PR #50 is the server-side half: it stops writing empty admin fields over stored ones, which protects already-deployed clients that will not pick this library up for a while.

Test plan

  • ping_resolves_details_when_init_has_not_run — with all four fields blanked, ping reports the resolved version, admin email and admin name
  • ping_does_not_re_resolve_details_already_set — asserts get_plugin_data and get_users are never called when values are present
  • Full suite: 64 tests, 119 assertions, green
  • Verified the new test fails against the old source ('2.5.0.5-feed' vs '') and passes with the change
  • phpcs net-zero: the two new hits in Integration are the get_users() array's existing sniff warnings, moved out of Updater (16→14). Total across the three files is 42 before and after

Note

Both this and #20 add a 1.4.0 heading to CHANGELOG.md, so merging both will conflict there — trivial to resolve by combining the bullets under one heading.

🤖 Generated with Claude Code

shazzad and others added 2 commits August 5, 2026 05:55
Activating a plugin includes its file and fires activate_{file} after
`init` has already passed, so the callback registered in the Integration
constructor never runs. Tracker::product_activated() then pinged with
admin_email and admin_name empty, and the server wrote those blanks over
the stored contact details.

product_version escaped only by accident: product_activated() calls
clear_updates_transient() first, which fires the update_plugins transient
filter and backfills the version from $transient->checked.

- Add Integration::prepare_product_data(), filling only what is missing
  unless forced, so the normal ping path does no extra work
- Updater::init() delegates to it with $force, keeping today's behaviour
- Client::ping() calls it, making the payload complete whatever the hook
  timing

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@shazzad
shazzad merged commit e450d2a into main Aug 5, 2026
1 check passed
@shazzad
shazzad deleted the fix/ping-resolves-own-product-data branch August 5, 2026 00:02
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