Summary
v1.0.0-beta.6 added Request::useNetworkLicenceFor(string $pluginFile) and the network_home_url() branch in Request::licensedSiteUrl(). That branch is only reachable if the host plugin calls the setter. PremiumServiceProvider already receives exactly the value it needs and does not use it for this, so every consumer has to discover and repeat the same one-liner — and a consumer that does not is silently billed per subsite.
Where
src/Container/PremiumServiceProvider.php (current main):
:73-87 — __construct(ClientConfig $config, string $pluginBasename, ?EncryptorInterface $encryptor = null), which validates $pluginBasename is non-empty and stores it at :83.
:139 — the only consumer of $this->pluginBasename, passing it to PluginUpdater.
wire() at :131 never calls Request::useNetworkLicenceFor().
src/Support/Request.php:
useNetworkLicenceFor() sets self::$pluginFile.
networkActivatedPlugin() returns it, and its docblock says null means "this site answers for itself — the safe direction, since it counts more sites rather than fewer".
licensedSiteUrl() reaches network_home_url() only when that value is non-null and is_plugin_active_for_network() agrees.
The constructor's own docblock at :30 even gives the example value in the shape the setter wants: pluginBasename: 'wp-statistics-premium/wp-statistics-premium.php'.
Why it matters
LicenseManager reads Request::currentDomain() in three places — activate(), deactivate() and validate() — so a host that has not wired the setter sends the subsite's own address on every licence call. On a network-activated install of 40 subsites that is 40 activations against a licence bought once.
It fails in the commercially safe direction and the customer-hostile one, which is why it is easy to ship: nobody gets free seats, and the customer is told they are out of seats with nothing on any screen explaining why. It surfaces as a support ticket, not as a bug report.
Suggested fix
Call it in wire() (or in the constructor after the validation), from the value already held:
Request::useNetworkLicenceFor($this->pluginBasename);
That makes the beta.6 feature work by default for every consumer, and keeps the explicit setter for hosts that construct Request usage without the provider. It changes behaviour only where is_plugin_active_for_network() is already true, so a single-site install and a per-site-activated network are both unaffected.
If you would rather it stay opt-in, that is a reasonable call too — but then it is worth saying so in the beta.6 release note and in the useNetworkLicenceFor() docblock, because the current shape reads like an oversight rather than a decision.
How this was found
Reviewing the beta.6 bump into a consumer plugin. grep -rn useNetworkLicenceFor across that repository returned exactly one line — the declaration in the vendored SDK — and zero call sites, several days after the bump merged.
Read against this repository's current main; the line numbers above are from it, not from the vendored copy.
Not this issue
#6 (a refused licence retried forever) is unrelated and still open; beta.6 does not contain it.
Summary
v1.0.0-beta.6addedRequest::useNetworkLicenceFor(string $pluginFile)and thenetwork_home_url()branch inRequest::licensedSiteUrl(). That branch is only reachable if the host plugin calls the setter.PremiumServiceProvideralready receives exactly the value it needs and does not use it for this, so every consumer has to discover and repeat the same one-liner — and a consumer that does not is silently billed per subsite.Where
src/Container/PremiumServiceProvider.php(currentmain)::73-87—__construct(ClientConfig $config, string $pluginBasename, ?EncryptorInterface $encryptor = null), which validates$pluginBasenameis non-empty and stores it at:83.:139— the only consumer of$this->pluginBasename, passing it toPluginUpdater.wire()at:131never callsRequest::useNetworkLicenceFor().src/Support/Request.php:useNetworkLicenceFor()setsself::$pluginFile.networkActivatedPlugin()returns it, and its docblock says null means "this site answers for itself — the safe direction, since it counts more sites rather than fewer".licensedSiteUrl()reachesnetwork_home_url()only when that value is non-null andis_plugin_active_for_network()agrees.The constructor's own docblock at
:30even gives the example value in the shape the setter wants:pluginBasename: 'wp-statistics-premium/wp-statistics-premium.php'.Why it matters
LicenseManagerreadsRequest::currentDomain()in three places —activate(),deactivate()andvalidate()— so a host that has not wired the setter sends the subsite's own address on every licence call. On a network-activated install of 40 subsites that is 40 activations against a licence bought once.It fails in the commercially safe direction and the customer-hostile one, which is why it is easy to ship: nobody gets free seats, and the customer is told they are out of seats with nothing on any screen explaining why. It surfaces as a support ticket, not as a bug report.
Suggested fix
Call it in
wire()(or in the constructor after the validation), from the value already held:That makes the beta.6 feature work by default for every consumer, and keeps the explicit setter for hosts that construct
Requestusage without the provider. It changes behaviour only whereis_plugin_active_for_network()is already true, so a single-site install and a per-site-activated network are both unaffected.If you would rather it stay opt-in, that is a reasonable call too — but then it is worth saying so in the beta.6 release note and in the
useNetworkLicenceFor()docblock, because the current shape reads like an oversight rather than a decision.How this was found
Reviewing the beta.6 bump into a consumer plugin.
grep -rn useNetworkLicenceForacross that repository returned exactly one line — the declaration in the vendored SDK — and zero call sites, several days after the bump merged.Read against this repository's current
main; the line numbers above are from it, not from the vendored copy.Not this issue
#6(a refused licence retried forever) is unrelated and still open;beta.6does not contain it.