DrPlugin

Update client for your plugins

Updated October 24, 2026

Add WordPress update notices, changelogs and one-click updates to a plugin you sell through a TierMint store.

What the client does

The update client is one PHP file, tiermint-update-client.php, with one class, TierMint_Update_Client. You ship it inside the plugin you sell. On your customer's site it asks your store for new versions, and WordPress then treats your plugin like any other:

  • The Plugins screen shows that a new version is available, with a link to the version details and an update now link.
  • The version details window shows your changelog and the version's requirements.
  • update now installs the new version in one click.
  • The Enable auto-updates toggle works.

A plugin row on the WordPress Plugins screen with a notice that a new version is available

The store renders the changelog, so your plugin holds no product data and needs no build step. The class uses only WordPress functions.

Download the client

The client is not inside the TierMint plugin. Download tiermint-client.zip from drplugin.com. It holds the update client, tiermint-update-client.php, and the license verifier, tiermint-license-verifier.php, which checks the signed license answers your store sends when it runs TierMint Pro. You do not need to buy anything or sign in to download it. When either file changes, we replace the zip at the same link.

Add the client to your plugin

  1. On your store, open the product in TierMint → Products. Turn on Licensed product and set Update slug to your plugin's folder name. Note the product's slug from its permalink: the client sends it as product_slug.
  2. Copy tiermint-update-client.php into your plugin, for example into an includes folder.
  3. Load it and create the client once, early, in your main plugin file:
require __DIR__ . '/includes/tiermint-update-client.php';

new TierMint_Update_Client(
	array(
		'api_url'      => 'https://yourstore.example/wp-json/tiermint/v1',
		'product_slug' => 'orbit-forms',
		'plugin_file'  => __FILE__,
		'license_key'  => get_option( 'orbit_forms_license_key', '' ),
	)
);

The constructor registers its own WordPress filters, so there is nothing else to call.

Option Required Meaning
api_url Yes Your store's TierMint REST base, ending in /wp-json/tiermint/v1.
product_slug Yes The product's catalog slug, the same one the store's licensing routes use.
plugin_file Yes Your main plugin file, passed as __FILE__. The client reads the installed version from its header, so you never hard-code a version.
license_key No The customer's license key, from wherever your settings store it. While it is empty, the store refuses the check and WordPress shows no update for your plugin.
channel No A release channel to follow, such as beta. Empty means stable. A store that runs TierMint Pro reads it. Other stores ignore it.

Your release zips must contain your plugin folder, named after the update slug. The update server page explains the check TierMint runs on each upload.

How it works

The client hooks into three WordPress filters on the customer's site.

pre_set_site_transient_update_plugins runs on each WordPress update check. The client asks your store's /update-check route about your plugin and compares the answer with the installed version. When the store has a newer version, your plugin goes into the update list with that version and its download link. When the site is up to date, the client says so, which keeps the auto-update toggle working. Because the client compares against the installed version each time, a plugin that just updated stops offering the version it now runs.

plugins_api fills the version details window. It shows your plugin's name, the new version, the required WordPress and PHP versions, the tested-up-to version and the changelog. The Description tab shows the plugin name and "See the changelog tab for the latest changes."

The WordPress version details window on its Changelog tab, showing a changelog served by a TierMint store

upgrader_pre_download runs when the customer updates. A download link from your store works for only five minutes, while the update notice can be hours old. So the client clears its cache, asks your store for a fresh link and downloads the package with it. If that fails, WordPress shows "Could not refresh the download link for this update. Please try updating again." or "The update package could not be downloaded. Please try updating again." These two messages are in English only.

Caching and the grace period

The client does not call your store on every page load. It keeps each answer from your store for 12 hours, including an answer that says the license is not valid. This keeps each site far below the store's rate limits.

When the 12 hours are up and your store cannot be reached, the client keeps using the last good answer for up to 72 hours from when it fetched it. Unreachable here means a timeout after 15 seconds, a connection error or any answer other than 200. An outage at your store does not hide a pending update. After 72 hours with no answer, the client reports no update for your plugin until the store answers again. It never breaks the customer's site.

The customer's site can change the 72 hours with the tiermint_client_grace_hours filter. A value of 0 turns the grace period off.

add_filter(
	'tiermint_client_grace_hours',
	function () {
		return 24;
	}
);

The cache is stored per store URL, product slug, license key and channel, so a new license key gets its own check. To force a fresh check, for example from a "Check for updates" button in your settings, call flush_cache() on your client:

// Keep the instance you create at load time, for example in a global.
global $my_plugin_update_client;
$my_plugin_update_client = new TierMint_Update_Client( $options );

// Later, when the customer asks for a fresh check:
$my_plugin_update_client->flush_cache();

Creating a second instance registers the update filters again, so call flush_cache() on the first one.

When the license is not valid

An expired, disabled or unknown license does not hide the update. The customer still sees that a new version exists and can read its changelog. What changes is the package: the store sends no download link. WordPress then lists the update with "Automatic update is unavailable for this plugin." and installs nothing.

The store also sends an upgrade notice, such as "Your license has expired. To receive this update, buy a new license and use its key." The client passes it to WordPress, which shows it next to the update on Dashboard → Updates. Once the site has a valid key, its next check brings the download link.

The client only controls updates. It never switches off the plugin the customer already installed. If your plugin should act on the license status, call the validate route from your own code.

Use the client in more than one plugin

If a site runs several plugins that each bundle this file, the file loads only once. It checks class_exists first, so the first copy loaded wins and the other plugins use that class. That works, but the first copy decides how all of them behave, even if it is an older version of the file.

To keep each plugin independent, rename the class to a name of your own. Replace every TierMint_Update_Client with, for example, Orbit_Forms_Update_Client, in the client file and in your new call.

Release channels with TierMint Pro

The channel option has an effect only when your store runs TierMint Pro. With Pro, the store offers beta and release candidate drafts to the sites that ask for them. A store without Pro ignores the option and serves its newest published release. The release channels page explains how to offer a build.

Common questions

Why does a new release not show on a customer's site yet?

The client keeps each answer for 12 hours, and WordPress checks for plugin updates on its own schedule. The site sees the new version on the first check after its cache runs out. Calling flush_cache() makes the client ask your store on the next check.

Does the client work for themes?

No. It hooks into the plugin update filters only, and the store's package check looks for a plugin header.