Tutorial• April 2026
How to Add License Keys to a WordPress Plugin
A practical guide to adding license key validation to any WordPress plugin using the KeyPort REST API with real PHP examples.
ER
Emily RodriguezAuthor • 5 min read
If you're selling a premium WordPress plugin, you need license key enforcement. Without it, a buyer can share your plugin ZIP and anyone can install it for free. This guide adds real enforcement using the KeyPort API — all in PHP, no dependencies.
Step 1 — Create Your Product on KeyPort
Sign up at app.keyport.sbs. Create an organization, then a product called "Your Plugin Name." Copy your product API key. Store it in wp-config.php, not in the plugin file itself.
Step 2 — Settings Page for the License Key
<?php
function my_plugin_render_license_settings() {
$license_key = get_option('my_plugin_license_key', '');
$license_status = get_option('my_plugin_license_status', null);
?>
<div class="my-plugin-license">
<h2>License</h2>
<?php if ($license_status === 'active'): ?>
<p style="color: green">✓ License active</p>
<?php elseif ($license_status): ?>
<p style="color: red">Issue: <?= esc_html($license_status) ?></p>
<?php endif; ?>
<form method="post" action="options.php">
<?php settings_fields('my_plugin_settings'); ?>
<input type="text" name="my_plugin_license_key"
value="<?= esc_attr($license_key) ?>"
placeholder="XXXX-XXXX-XXXX-XXXX" style="width: 300px">
<?php submit_button('Save License', 'primary', 'submit', false); ?>
</form>
</div>
<?php }Step 3 — Validate the License Key
<?php
function my_plugin_validate_license(string $key): array {
$response = wp_remote_post('https://api.keyport.sbs/api/v1/validate', [
'timeout' => 8,
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . MY_PLUGIN_API_KEY,
],
'body' => wp_json_encode(['license_key' => $key]),
]);
if (is_wp_error($response)) {
// Network error — use cached result (24-hour grace)
return get_transient('my_plugin_license_cache') ?: [
'valid' => false, 'status' => 'network_error'
];
}
$data = json_decode(wp_remote_retrieve_body($response), true);
if ($data['valid']) {
set_transient('my_plugin_license_cache', $data, DAY_IN_SECONDS);
update_option('my_plugin_license_status', 'active');
} else {
update_option('my_plugin_license_status', $data['status']);
}
return $data;
}
// Re-validate on settings save
add_action('update_option_my_plugin_license_key', function($old, $new) {
my_plugin_validate_license($new);
}, 10, 2);Step 4 — Gate Premium Features
<?php
function my_plugin_is_licensed(): bool {
return get_option('my_plugin_license_status') === 'active';
}
// In your premium feature code:
if (!my_plugin_is_licensed()) {
echo '<p>This feature requires a valid license. '
. '<a href="https://yourdomain.com/pricing">Get a license →</a></p>';
return;
}
// Full feature code here...Step 5 — Gate Plugin Updates (Optional)
<?php
add_filter('site_transient_update_plugins', function($transient) {
if (!my_plugin_is_licensed()) {
$plugin_file = 'my-plugin/my-plugin.php';
unset($transient->response[$plugin_file]);
}
return $transient;
});Testing Checklist
- [ ] Valid key → shows "active"
- [ ] Invalid key → shows error
- [ ] Expired key → shows "expired"
- [ ] No network → uses 24-hour cached result
- [ ] Premium features hidden without valid license
- [ ] Update notification hidden without valid license