Private release previewNo live purchasesRelease details ↗

EN · ORIGINAL REPOSITORY DOCUMENT

Paid WordPress integration

Original English text. Commands and evidence apply to the revision and environment stated in the document.

product/licensing/wordpress-admin/README.paid.md

On this page

The paid WordPress plugin can use src/Plugin/OriginalEntitlements.php alongside its inherited feature set. Root integration adds the trait to Plugin, links Premium access into its existing administration, and owns the WordPress updater filters. This adapter does not re-enable vendor licensing/update APIs, replace upstream distribution rights, gate cache operations, or alter cache configuration. The operator Go service serves authorized original artifacts only; project update ZIPs retain upstream notices and the owner-confirmed reuse record in PROVENANCE.md. The entitlement service does not grant upstream rights.

Public plugin API

  • bootOriginalEntitlements() registers admin menu/post, the optional refresh callback and cleanup callbacks only. It does not construct the binding, read credentials, schedule work or contact a service during plugin/frontend boot.
  • originalEntitlementStatus() returns locally verified status. Invalid/missing operator configuration or administrative capability returns generic unavailable state with premium_update_access=false; no remote request or fatal exception.
  • originalEntitlementPageUrl() points to objectcache-original-entitlement in network/single-site Settings.
  • originalEntitlementAction(operation,input) requires a POST, the applicable WordPress administrator capability, and the nonce for original_entitlement_admin_action. Operations are save, activate, check, deactivate, updates and download. The binding repeats authorization.
  • originalEntitlementUpdateMetadata(input) returns verified version/checksum only, storing no bearer token. Transient/plugin-metadata readers must use the local summary/status; they must never call this network method implicitly.
  • originalEntitlementDownload(input) obtains fresh /updates metadata and then /download, verifies SHA-256 and an independent eight-MiB maximum, and returns bytes. The admin POST callback streams an attachment without installing it.

Configuration uses the existing operator-fixed ORIGINAL_ENTITLEMENT_ADMIN_CONFIG: HTTPS service origin, trusted public keys and an already prepared writable private cache directory outside WordPress web roots.

Define the configuration in private wp-config.php deployment configuration; do not install the separate standalone admin prototype alongside this adapter:

define('ORIGINAL_ENTITLEMENT_ADMIN_CONFIG', [
    'service_origin' => 'https://licenses.operator.example',
    'public_keys' => ['fixture-v1' => $operatorPublicVerificationPem],
    'cache_directory' => '/private/operator/entitlement-cache',
    'enable_refresh_cron' => false,
]);

The public verification PEM comes from the operator. No signing key belongs in WordPress. Prepare the private directory with ownership for the PHP process and keep it outside every published web directory. The backend operator approves the site origin and issues the license before the administrator opens Premium access, saves the license, activates, and checks update metadata. The Plugins screen then offers an authorized newer original package through the core updater. Automatic plugin updates remain disabled; explicit update installation rechecks the grant and exact selected version/checksum with the service. A revoked grant, outage or changed package blocks the update without disabling cache operations.

The WP-CLI-only loopback exception remains available to explicit disposable tests. Credentials stay in the original admin option, displayed only as fingerprints. Multisite identity binds to network_home_url('/'), so a mapped subsite cannot change the network-wide installed origin; single-site binds to home_url('/').

WordPress core updater boundary

AdminBinding::downloadForUpgrade(expectedVersion,expectedSha,pluginBasename) requires update_plugins capability and either explicit WP_CLI === true or a genuine WordPress request nonce for upgrade-plugin_<basename> or bulk-update-plugins, or the core AJAX updates nonce bound to update-plugin and this plugin’s posted basename. It does not forge a product nonce or change the request method. Fresh server metadata must exactly match the selected version/checksum; then the existing client verifies downloaded bytes and the independent size limit. No remote URL is accepted from package metadata or a posted field. Root’s updater bridge must also bind the hook’s plugin basename and synthetic internal package URI to the locally verified selected summary and catch errors as WP_Error. It must never turn this method into an unrestricted remote package downloader.

Optional refresh lifecycle

The literal operator option enable_refresh_cron => true enables bounded refresh; it is off by default. A successful explicit activate/check can schedule the original_paid_entitlement_refresh event hourly, deduplicated through wp_next_scheduled. No schedule is created on boot, init, GET or cache operations. refreshOriginalEntitlementScheduled() runs only in genuine cron or explicit WP-CLI context, checks the operator opt-in before constructing the binding, and calls only /entitlement. It never issues, activates, downloads or checks updates. The binding exposes refreshForScheduledCheck() for this trusted callback only.

A successfully verified inactive/revoked/expired denial clears this adapter’s schedule. Outages retain the existing verified deadlines and schedule, including when local grace expires, so recovery can still be observed. Explicit successful deactivation and plugin deactivation/uninstall callbacks clear only this hook. Root lifecycle integration can also invoke clearOriginalEntitlementSchedule() for an inactive-plugin uninstall path. No other plugin or cron event is altered.

WordPress’s single Plugin_Upgrader::upgrade() silently deactivates an active plugin; the browser/core caller completes reactivation. A direct CLI caller must perform a normal network/single-site activation after the successful upgrade. The updater completion callback refreshes an existing owned drop-in from the new stub, with fresh metadata, for both singular and bulk core completion events. It does not install an absent drop-in or overwrite a foreign one.

Targeted validation

php -n product/licensing/wordpress-admin/test.php
php -n product/licensing/wordpress-admin/paid-trait-test.php

Focused tests passed on PHP 8.3.28 in the cached isolated Linux image. They cover native product/core-upgrade authorization before HTTP, CLI capability gating, version/checksum mismatch, tampered downloads, eight-MiB bounds, bearer omission, origin consistency under a mapped subsite, default-off cron, opt-in refresh-only transport and outage deadlines. Trait tests cover lazy boot, unavailable/bad configuration status, nonce/capability rejection, schedule cleanup isolation and local page rendering. Real installed paid-plugin/Go/upgrader validation is owned by the parent integration runner; these focused doubles alone do not prove that end-to-end path or an authorized distributable paid release.

Payment verification, checkout/customer operations and key recovery/rotation remain separate operational gates. The owner confirmed upstream reuse authority; the original license and attribution are retained in the packaged project. No production account, key, payment or deployment is created by this integration.