Auto-Updates
LicenceForge integrates with the WordPress plugin and theme update system to deliver new versions to licensed users. Updates are only shown when the licence is active, the server version is newer, and the download package passes SHA-256 hash verification.
How it works
The WPLF_Client_Updater class (part of the 3-class system) hooks into WordPress core to inject update information for your product. The process runs automatically whenever WordPress checks for updates.
WordPress hooks
The updater registers two filters for plugin updates:
| Filter | Purpose |
|---|---|
pre_set_site_transient_update_plugins |
Injects update data into the WordPress update transient when a newer version is available on the LicenceForge server. |
plugins_api |
Provides detailed plugin information (changelog, banners, icons, compatibility data) for the update detail modal shown when a user clicks "View version details". |
Theme hooks
The WPLF_Licensing drop-in class also supports theme updates via the equivalent theme filters:
| Filter | Purpose |
|---|---|
pre_set_site_transient_update_themes |
Injects update data into the WordPress theme update transient. |
themes_api |
Provides detailed theme information for the update detail modal. |
Note
Theme update support is available through the WPLF_Licensing drop-in class. The 3-class WPLF_Client_Updater handles plugin updates only.
Update conditions
The updater only injects update information into the WordPress transient when all of the following conditions are met:
- The licence is active (validated and not expired, suspended, or cancelled).
- The server version is greater than the currently installed version (compared using
version_compare()). - The site is within the rollout percentage for the release (see Rollout awareness below).
If the licence is inactive, the updater does not show an available update. Instead, it displays an "Licence: Inactive" badge on the plugins list to alert the site administrator.
Update response data
When the client queries the LicenceForge server for update information, the server returns a JSON object containing the following fields:
{
"new_version": "2.5.0",
"package": "https://licences.example.com/wplf/v1/downloads/my-plugin?token=eyJ0eXAi...",
"package_hash": "sha256:a3f8c2d1e4b5a6f7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1",
"tested": "6.7",
"requires": "6.2",
"requires_php": "7.4",
"changelog": "<h4>2.5.0</h4><ul><li>Added conditional logic builder</li><li>Fixed form submission race condition</li></ul>",
"icons": {
"1x": "https://licences.example.com/assets/icon-128x128.png",
"2x": "https://licences.example.com/assets/icon-256x256.png"
},
"banners": {
"low": "https://licences.example.com/assets/banner-772x250.png",
"high": "https://licences.example.com/assets/banner-1544x500.png"
},
"rollout_percentage": 100
}
Package download
The package URL includes a signed token that authorises the download. This token has a default expiry of 5 minutes from the time the update response is generated. If the download does not begin within this window, WordPress will receive a 403 response and the update will fail gracefully.
Warning
Do not cache or redistribute package URLs. Each URL contains a single-use signed token that expires quickly. The server generates a fresh token on every update check.
SHA-256 hash verification
Every package download is verified against a SHA-256 hash to ensure the file has not been tampered with in transit. This is a critical security measure.
Verification flow
- The update response includes a
package_hashfield containing the expected SHA-256 hash, prefixed withsha256:. - After WordPress downloads the package,
WPLF_Client_Updaterintercepts the response via thehttp_responsefilter. - The updater computes the SHA-256 hash of the downloaded file.
- If the computed hash matches the expected hash, the update proceeds normally.
- If the hashes do not match, the update is aborted and the downloaded file is discarded.
Danger
A hash mismatch indicates the downloaded file differs from what the server intended to deliver. This could be caused by a corrupted download, a CDN issue, or a man-in-the-middle attack. The update is rejected to protect the site.
Rollout awareness
The updater respects the rollout_percentage value from the server response. When a product release is configured with a staggered rollout (e.g. 25%), only a subset of sites will see the update as available.
The client determines eligibility by hashing the site URL and checking whether the resulting value falls within the rollout window. This produces a deterministic, evenly distributed result -- the same site will consistently either see or not see the update for a given rollout percentage.
Once the rollout percentage reaches 100, all licensed sites will see the update. See Rollouts for server-side configuration.
Inactive licence badge
When the licence is not active, the updater adds a red "Licence: Inactive" badge to the plugin's row on the Plugins page. This serves as a visible reminder to the site administrator without interfering with the plugin's normal operation.
The badge is rendered via the after_plugin_row action and styled inline. It does not prevent the plugin from functioning -- it only indicates that automatic updates are unavailable until the licence is reactivated.
Initialization
The updater requires no configuration beyond a WPLF_Client instance. It reads the product slug, API URL, and plugin file path from the client.
3-class system
require_once __DIR__ . '/includes/class-wplf-client.php';
require_once __DIR__ . '/includes/class-wplf-client-updater.php';
$client = new WPLF_Client( 'my-plugin', 'https://licences.example.com', __FILE__ );
$updater = new WPLF_Client_Updater( $client );
Drop-in system
With the WPLF_Licensing drop-in, auto-updates are enabled by default. No additional initialization is required -- the drop-in handles both plugin and theme updates automatically when a licence is registered.
require_once __DIR__ . '/includes/class-wplf-licensing.php';
WPLF_Licensing::register( [
'product_slug' => 'my-plugin',
'api_url' => 'https://licences.example.com',
'plugin_file' => __FILE__,
] );
Next steps
- WordPress Integration (3-Class) -- Full setup guide for the client library
- Hooks and Filters -- Customise update behaviour with client-side filters
- Rollouts -- Configure staggered version rollouts on the server
- Download Security -- Token signing and hash verification details