| 1 |
# StoreEngine License Management Client SDK For WordPress |
| 2 |
|
| 3 |
This *StoreEngine License Management Client SDK for WordPress* is a lightweight, developer-friendly toolkit that helps |
| 4 |
WordPress plugin and theme authors securely manage licensing, updates, and insights for their premium products. |
| 5 |
|
| 6 |
## Features |
| 7 |
|
| 8 |
By integrating this SDK, you can: |
| 9 |
|
| 10 |
1. Automate license activation and deactivation for customers who purchase through your own eCommerce site powered by the StoreEngine plugin. |
| 11 |
2. Deliver secure and seamless automatic updates to premium plugins and themes directly within WordPress. |
| 12 |
3. Track and monitor license usage with detailed activation and deactivation logs, ensuring better compliance visibility. |
| 13 |
4. Gain actionable insights with usage analytics, showing how your products are used in real-world environments. |
| 14 |
5. Run in-product promotions and marketing campaigns to cross-sell or upsell your other free or premium offerings. |
| 15 |
6. Integrated Isolated per-client REST API for license and insights management. |
| 16 |
7. Full support for theme license management and automatic updates. |
| 17 |
|
| 18 |
Whether you’re an independent developer or managing a portfolio of WordPress products, this SDK is designed to simplify |
| 19 |
license enforcement, streamline product updates, and provide valuable insights—all while reducing your development overhead. |
| 20 |
|
| 21 |
## Installation |
| 22 |
|
| 23 |
There are two ways to install this SDK. |
| 24 |
|
| 25 |
1. Download the latest release version and include it in your project like you would with any other third-party library. |
| 26 |
2. Install via composer. |
| 27 |
|
| 28 |
### Download and use as 3rd Party library |
| 29 |
|
| 30 |
Download the latest [](https://github.com/imrantushar/storeengine-sdk-for-wordpress/releases/latestrelease file](https://github.com/imrantushar/storeengine-sdk-for-wordpress/releases/latest](https://github.com/imrantushar/storeengine-sdk-for-wordpress/releases/latest) and extract in a folder (e.g `library/storeengine`) of your plugin/theme. |
| 31 |
Now include the `init.php` file in your plugin/theme. This file must be loaded before the `plugins_loaded` hook. |
| 32 |
|
| 33 |
```php |
| 34 |
require_once __DIR__ . '/library/storeengine/init.php' |
| 35 |
``` |
| 36 |
|
| 37 |
### Install via Composer |
| 38 |
|
| 39 |
To install via `composer` please add this repository in your project's `composer.json` file. Then require `storeengine/wordpress-sdk`. |
| 40 |
_This SDK is not yet available in [](https://packagist.org/packagist.org](https://packagist.org/](https://packagist.org/) (will be available soon)._ |
| 41 |
|
| 42 |
```json |
| 43 |
{ |
| 44 |
"repositories": [ |
| 45 |
{ |
| 46 |
"type": "vcs", |
| 47 |
"url": "https://github.com/imrantushar/storeengine-sdk-for-wordpress.git" |
| 48 |
} |
| 49 |
], |
| 50 |
"require": { |
| 51 |
"storeengine/wordpress-sdk": "^1.3" |
| 52 |
} |
| 53 |
} |
| 54 |
``` |
| 55 |
|
| 56 |
Then run composer update command from the terminal. |
| 57 |
|
| 58 |
```bash |
| 59 |
composer update |
| 60 |
``` |
| 61 |
|
| 62 |
Include the Composer autoloader in your plugin/theme. |
| 63 |
|
| 64 |
```php |
| 65 |
require_once __DIR__ . '/vendor/autoload.php' |
| 66 |
``` |
| 67 |
|
| 68 |
> **PS:** Don’t worry about “class/function already exists” errors or version conflicts when other plugins or themes use this SDK. |
| 69 |
> <br> |
| 70 |
> The SDK is designed with a fail-safe mechanism that always loads the latest available version if multiple copies are found within a WordPress installation. |
| 71 |
|
| 72 |
### Important: loading order when multiple plugins bundle the SDK |
| 73 |
|
| 74 |
The fail-safe "newest version wins" election only works for copies whose |
| 75 |
`init.php` **actually executes**. Composer's `autoload_files` (what |
| 76 |
`vendor/autoload.php` runs) de-duplicates included files by a *package-stable* |
| 77 |
hash — the hash is derived from the package name + file path, **not** the |
| 78 |
absolute vendor location. So if two active plugins each ship |
| 79 |
`storeengine/wordpress-sdk` via Composer, only the **first** plugin's |
| 80 |
`vendor/autoload.php` includes `init.php`; every other copy's `init.php` is |
| 81 |
silently skipped and never registers its version. If that first plugin bundles |
| 82 |
an **older** SDK, the newer copies lose the election even though they're newer. |
| 83 |
|
| 84 |
To be immune to load order, **require `init.php` directly** instead of relying |
| 85 |
on Composer's autoload-files (this is what StoreEngine core does): |
| 86 |
|
| 87 |
```php |
| 88 |
// Loads this copy's init.php unconditionally, before plugins_loaded. |
| 89 |
require_once __DIR__ . '/vendor/storeengine/wordpress-sdk/init.php'; |
| 90 |
// (vendor/autoload.php is still fine to load for your other classes.) |
| 91 |
``` |
| 92 |
|
| 93 |
Each `init.php` guards itself against re-declaration, so requiring it directly |
| 94 |
is safe even when several plugins do the same — every copy registers its |
| 95 |
version and the newest genuinely wins. If your product is a **pro add-on that |
| 96 |
depends on a free plugin already shipping the SDK**, prefer not bundling the SDK |
| 97 |
at all and just calling the global `se_license_init()` the free plugin exposes. |
| 98 |
|
| 99 |
## Usage |
| 100 |
|
| 101 |
Integrating the SDK into your plugin or theme is designed to be drop-in simple. |
| 102 |
The core entry point is a single helper function: `se_license_init()`, which wires up licensing, updates, and insights |
| 103 |
automatically for your product. |
| 104 |
|
| 105 |
This function should be called as early as possible within the WordPress load order — typically on the `plugins_loaded` hook. |
| 106 |
|
| 107 |
```php |
| 108 |
add_action( 'plugins_loaded', function () { |
| 109 |
se_license_init( [ |
| 110 |
'package_file' => __FILE__, |
| 111 |
'package_name' => __( 'Your Amazing Plugin', 'textdomain' ), |
| 112 |
'product_id' => 27870, |
| 113 |
'is_free' => false, |
| 114 |
'slug' => 'your-amazing-plugin', |
| 115 |
'basename' => plugin_basename( __FILE__ ), |
| 116 |
'package_type' => 'plugin', |
| 117 |
'package_version' => '1.0.0', |
| 118 |
'license_server' => 'https://your-website.com', |
| 119 |
'product_logo' => plugins_url( 'assets/images/logo.svg', __FILE__ ), |
| 120 |
'store_dashboard_url' => 'https://your-website.com/dashboard/license-keys/', |
| 121 |
'terms_url' => 'https://your-website.com/terms-and-conditions/', |
| 122 |
'privacy_policy_url' => 'https://your-website.com/privacy-policy/', |
| 123 |
'ticket_recipient' => '[email protected]', |
| 124 |
'first_install_time' => get_option( 'your-amazing-plugin-first-installation-time' ), |
| 125 |
'optin_notice_delay' => 3 * DAY_IN_SECONDS, # Optional, Default is 3 days from installation. |
| 126 |
'init_restapi' => true, # Enable isolated REST API for this product. |
| 127 |
] ); |
| 128 |
} ); |
| 129 |
``` |
| 130 |
|
| 131 |
### Deploy Free Plugins |
| 132 |
|
| 133 |
Free WordPress plugin can be deployed with StoreEngine, and SDK will now can auto-update the plugin directly from the deployed server. |
| 134 |
This can be achieved by setting `is_free` to `true` and setting `use_update` to true. Updater will fetch package information without any active license. |
| 135 |
|
| 136 |
```php |
| 137 |
add_action( 'plugins_loaded', function () { |
| 138 |
se_license_init( [ |
| 139 |
'package_file' => __FILE__, |
| 140 |
'package_name' => __( 'Your Amazing Plugin', 'textdomain' ), |
| 141 |
'product_id' => 27870, |
| 142 |
'is_free' => true, |
| 143 |
'use_update' => true, |
| 144 |
'slug' => 'your-amazing-plugin', |
| 145 |
'basename' => plugin_basename( __FILE__ ), |
| 146 |
'package_type' => 'plugin', |
| 147 |
'package_version' => '1.0.0', |
| 148 |
'license_server' => 'https://your-website.com', |
| 149 |
'product_logo' => plugins_url( 'assets/images/logo.svg', __FILE__ ), |
| 150 |
'store_dashboard_url' => 'https://your-website.com/dashboard/license-keys/', |
| 151 |
'terms_url' => 'https://your-website.com/terms-and-conditions/', |
| 152 |
'privacy_policy_url' => 'https://your-website.com/privacy-policy/', |
| 153 |
'ticket_recipient' => '[email protected]', |
| 154 |
'first_install_time' => get_option( 'your-amazing-plugin-first-installation-time' ), |
| 155 |
'optin_notice_delay' => 3 * DAY_IN_SECONDS, # Optional, Default is 3 days from installation. |
| 156 |
'init_restapi' => true, # Enable isolated REST API for this product. |
| 157 |
] ); |
| 158 |
} ); |
| 159 |
``` |
| 160 |
|
| 161 |
### How it works |
| 162 |
- Automatic versioning & failsafe loading: If multiple plugins or themes bundle this SDK, WordPress will always load the |
| 163 |
latest version automatically, preventing conflicts or duplicate class errors. |
| 164 |
- Seamless UI integration: A “Manage License” menu item is automatically created for your users, with customizable branding (logo). |
| 165 |
- Secure API communication: All license activations, deactivations, and update checks are routed securely through your |
| 166 |
StoreEngine-powered server. |
| 167 |
- Future extensibility: Once enabled, upcoming features like usage analytics and in-product promotions (upcoming) can be |
| 168 |
toggled on with minimal additional code. |
| 169 |
|
| 170 |
|
| 171 |
> **For Plugin:** Call `se_license_init()` from the main plugin file (`your-plugin-slug/your-plugin-slug.php`). |
| 172 |
|
| 173 |
### Themes |
| 174 |
|
| 175 |
Themes are supported end-to-end: licensing UI, automatic updates, pre-swap |
| 176 |
package validation and one-click rollback all work the same as for plugins. Call |
| 177 |
`se_license_init()` from your theme's `functions.php`, on `after_setup_theme` |
| 178 |
(themes have no `plugins_loaded`). Set `package_type` to `theme` (or let the SDK |
| 179 |
auto-detect it), and use your theme's stylesheet folder as the `slug`: |
| 180 |
|
| 181 |
```php |
| 182 |
add_action( 'after_setup_theme', function () { |
| 183 |
se_license_init( [ |
| 184 |
'package_file' => get_stylesheet_directory() . '/functions.php', |
| 185 |
'package_name' => __( 'Your Amazing Theme', 'textdomain' ), |
| 186 |
'product_id' => 27871, |
| 187 |
'is_free' => false, |
| 188 |
'slug' => 'your-amazing-theme', // stylesheet folder name |
| 189 |
'package_type' => 'theme', |
| 190 |
'package_version' => wp_get_theme()->get( 'Version' ), |
| 191 |
'license_server' => 'https://your-website.com', |
| 192 |
// …same optional keys as the plugin example. |
| 193 |
] ); |
| 194 |
} ); |
| 195 |
``` |
| 196 |
|
| 197 |
The “Manage License” screen is added under **Appearance** for themes. |
| 198 |
|
| 199 |
## Isolated REST API |
| 200 |
|
| 201 |
The SDK includes a built-in REST API namespace (`storeengine-sdk/v1`) that is isolated for each plugin instance. This feature is disabled by default and can be enabled by setting `init_restapi` to `true` in the `se_license_init` call. |
| 202 |
|
| 203 |
### Endpoints |
| 204 |
Endpoints are prefixed with your plugin slug: `/wp-json/storeengine-sdk/v1/{slug}/` |
| 205 |
|
| 206 |
- **License Activation**: `POST /license/activate` (requires `license` parameter). |
| 207 |
- **License Deactivation**: `POST /license/deactivate`. |
| 208 |
- **License Status**: `GET /license/status` (use `?force=true` to skip cache). |
| 209 |
- **Insights Opt-in/Out**: `POST /insights/optin` (use `?opt_in=true/false`). |
| 210 |
|
| 211 |
All endpoints require the `manage_options` capability. |
| 212 |
|
| 213 |
## Events / Hooks |
| 214 |
|
| 215 |
The SDK fires documented lifecycle events so your plugin/theme can react to |
| 216 |
license and update changes. Every event is namespaced per-product, so subscribe |
| 217 |
through the client's `add_action()` helper (it prefixes the hook name for you): |
| 218 |
|
| 219 |
```php |
| 220 |
$client = se_license_init( [ /* … */ ] ); // or SE_License_SDK::get_registered_by_slug( 'your-slug' ) |
| 221 |
|
| 222 |
$client->add_action( 'license_activated', function ( $license ) { |
| 223 |
// e.g. flush caps, provision features, log. |
| 224 |
} ); |
| 225 |
``` |
| 226 |
|
| 227 |
| Event | Fired when | Args | |
| 228 |
| --- | --- | --- | |
| 229 |
| `license_activated` | A license is successfully activated. | `$license` | |
| 230 |
| `license_deactivated` | License deactivated by the user, or by a server verdict on the scheduled check. | `$license` | |
| 231 |
| `license_grace_expired` | The server was unreachable past the offline grace period, so the license failed closed. | `$license` | |
| 232 |
| `license_check_deferred` | A scheduled check couldn't reach the server but the license is still honoured (within grace). | `$license` | |
| 233 |
| `update_installed` | This product's files were updated in place (native "Update now"/bulk/auto-update, or the SDK installer). | `$previous_version` | |
| 234 |
| `update_failed` | An SDK-driven install failed. | `$wp_error, $target_version, $current_version` | |
| 235 |
|
| 236 |
### Updates and license state |
| 237 |
|
| 238 |
Updates for a pro product are gated on the license. The license server omits the |
| 239 |
download URL for an unlicensed site, and WordPress renders "Automatic update is |
| 240 |
unavailable for this plugin" whenever an update row has no `package`. Because the |
| 241 |
server response is cached locally, the SDK also: |
| 242 |
|
| 243 |
- drops the cached version info on every license lifecycle transition |
| 244 |
(`license_activated`, `license_deactivated`, `license_grace_expired`), so a |
| 245 |
download URL obtained under an active license cannot outlive it — this covers |
| 246 |
the PHP license form, the REST endpoints, WP-CLI and the scheduled re-check |
| 247 |
alike; and |
| 248 |
- blanks `package` / `download_link` for a pro product with no valid license as |
| 249 |
the update payload is injected, as a backstop for any payload cached before |
| 250 |
this behaviour existed. |
| 251 |
|
| 252 |
Free products are never gated, and a license inside its **offline grace period** |
| 253 |
still counts as valid — a server outage does not strip working updates. |
| 254 |
|
| 255 |
### Offline grace period |
| 256 |
|
| 257 |
If the license server can't be reached during the daily re-check (DNS/timeout/TLS |
| 258 |
failure, a blocked outbound request, or a 5xx), a previously-valid license keeps |
| 259 |
working for a grace window (default **14 days** since the last successful |
| 260 |
verification) instead of being deactivated by a transient outage. Configure it |
| 261 |
with the `license_grace_period` init arg (seconds; `0` = fail closed |
| 262 |
immediately) or the `{hook}_license_grace_period` filter. |
| 263 |
|
| 264 |
## Learn More |
| 265 |
|
| 266 |
Visit our official website [](https://storeengine.prostoreengine.pro](https://storeengine.pro](https://storeengine.pro) for more details on selling WordPress plugins and themes online. |
| 267 |
|
| 268 |
* [](https://storeengine.pro/docs/storeengine-license-management/Software Management Guide](https://storeengine.pro/docs/storeengine-license-management/](https://storeengine.pro/docs/storeengine-license-management/): Detailed instructions on how to sell software (WordPress plugin/theme) and deployment. |
| 269 |
* API Reference (coming soon): For handling other software/app license activation and automatic updates. |
| 270 |
|
| 271 |
## License and Attribution |
| 272 |
|
| 273 |
This project, **StoreEngine License Management Client SDK For WordPress**, is licensed under the GNU General Public License v3.0. |
| 274 |
|
| 275 |
This project includes code derived from **Action Scheduler** by Automattic, Inc., also licensed under the GNU GPL v3.0. |
| 276 |
|
| 277 |
See [](./license.txtlicense.txt](./license.txt](./license.txt) for license details. |
| 278 |
|
| 279 |
## Credits |
| 280 |
|
| 281 |
*StoreEngine License Management Client SDK for WordPress* is developed and maintained by [](http://kodezen.com/Kodezen](http://kodezen.com/](http://kodezen.com/). |
| 282 |
|
| 283 |
Collaboration is welcome! We’d love to work with you to improve this SDK. [](http://github.com/imrantushar/storeengine-license-management-client-sdk/pullsPull Requests](http://github.com/imrantushar/storeengine-license-management-client-sdk/pulls](http://github.com/imrantushar/storeengine-license-management-client-sdk/pulls) are highly appreciated. |
| 284 |
|
| 285 |
The versioned loading and initializer system of this SDK is based on and derived from [](https://actionscheduler.org/Action Scheduler](https://actionscheduler.org/](https://actionscheduler.org/), developed and maintained by [](https://automattic.com/Automattic](https://automattic.com/](https://automattic.com/), with significant early development contributed by [](https://flightless.us/Flightless](https://flightless.us/](https://flightless.us/). |
| 286 |
|