Skip to content

PremiumServiceProvider has the plugin basename and never passes it to Request::useNetworkLicenceFor(), so the network-licence branch is unreachable unless every host remembers to wire it #7

Description

@navidkashani

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions