15 KiB
WP Digital Download - Software Licensing Integration Guide
This guide shows developers how to integrate their WordPress plugins with the WP Digital Download licensing and update system.
Quick Start
1. Download the Integration Library
Download wpdd-plugin-updater.php
from your product page and include it in your plugin.
2. Minimal Integration
For the simplest integration with automatic license management:
<?php
/**
* Plugin Name: My Plugin
* Version: 1.0.0
*/
// Initialize updater with automatic settings page
if (!class_exists('WPDD_Plugin_Updater') && is_admin()) {
require_once plugin_dir_path(__FILE__) . 'includes/wpdd-plugin-updater.php';
new WPDD_Plugin_Updater(
__FILE__,
get_option('my_plugin_license_key', ''),
'https://your-store.com',
array('add_settings_page' => true)
);
}
This creates a license settings page under Settings → My Plugin License.
3. Full Integration
<?php
/**
* Plugin Name: My Awesome Plugin
* Version: 1.0.0
*/
// Include the WPDD updater library (check if class exists to avoid conflicts)
if (!class_exists('WPDD_Plugin_Updater')) {
require_once plugin_dir_path(__FILE__) . 'includes/wpdd-plugin-updater.php';
}
class My_Awesome_Plugin {
private $updater;
public function __construct() {
$this->init_updater();
}
private function init_updater() {
// Only initialize updater in admin area
if (!is_admin()) {
return;
}
$license_key = get_option('my_plugin_license_key', '');
$this->updater = new WPDD_Plugin_Updater(
__FILE__, // Main plugin file
$license_key, // License key from user
'https://your-store.com', // Your store URL
array(
'add_settings_page' => true // Add license settings page
)
);
}
}
new My_Awesome_Plugin();
Advanced Integration
Custom License Settings Page
If you want to integrate license management into your existing settings:
class My_Plugin_Settings {
private $updater;
public function __construct() {
$this->init_updater();
add_action('admin_menu', array($this, 'add_settings_page'));
add_action('admin_init', array($this, 'handle_license_actions'));
}
private function init_updater() {
// Check if updater class exists
if (!class_exists('WPDD_Plugin_Updater')) {
return;
}
$license_key = get_option('my_plugin_license_key', '');
$this->updater = new WPDD_Plugin_Updater(
MY_PLUGIN_FILE, // Define this constant to your main plugin file
$license_key,
'https://your-store.com',
array('add_settings_page' => false) // We'll handle settings ourselves
);
}
public function handle_license_actions() {
if (isset($_POST['activate_license'])) {
$license_key = sanitize_text_field($_POST['license_key']);
$result = $this->updater->activate_license($license_key);
if ($result['success']) {
update_option('my_plugin_license_key', $license_key);
add_settings_error('my_plugin', 'activated', 'License activated!', 'updated');
} else {
add_settings_error('my_plugin', 'error', $result['message'], 'error');
}
}
if (isset($_POST['deactivate_license'])) {
$result = $this->updater->deactivate_license();
if ($result['success']) {
delete_option('my_plugin_license_key');
add_settings_error('my_plugin', 'deactivated', 'License deactivated!', 'updated');
}
}
}
public function render_license_section() {
$license_key = get_option('my_plugin_license_key', '');
$is_valid = $this->updater ? $this->updater->validate_license() : false;
?>
<h3>License Settings</h3>
<table class="form-table">
<tr>
<th><label for="license_key">License Key</label></th>
<td>
<input type="text" id="license_key" name="license_key"
value="<?php echo esc_attr($license_key); ?>" class="regular-text" />
<?php if ($is_valid): ?>
<span style="color: green;">✓ Active</span>
<?php elseif (!empty($license_key)): ?>
<span style="color: red;">✗ Invalid</span>
<?php endif; ?>
<p class="description">
Enter your license key to receive automatic updates.
</p>
</td>
</tr>
</table>
<?php if (empty($license_key) || !$is_valid): ?>
<p>
<input type="submit" name="activate_license" class="button-primary" value="Activate License" />
</p>
<?php else: ?>
<p>
<input type="submit" name="deactivate_license" class="button-secondary" value="Deactivate License" />
</p>
<?php endif; ?>
<?php
}
}
Manual License Validation
For premium features or activation checks:
class My_Premium_Feature {
private $updater;
public function __construct() {
// Include updater if not already loaded
if (!class_exists('WPDD_Plugin_Updater')) {
require_once plugin_dir_path(__FILE__) . 'includes/wpdd-plugin-updater.php';
}
$license_key = get_option('my_plugin_license_key', '');
$this->updater = new WPDD_Plugin_Updater(
MY_PLUGIN_FILE,
$license_key,
'https://your-store.com'
);
// Only enable premium features if license is valid
if ($this->is_license_valid()) {
$this->enable_premium_features();
} else {
$this->show_license_notice();
}
}
private function is_license_valid() {
// Check if updater exists and validate license
return $this->updater ? $this->updater->validate_license() : false;
}
private function enable_premium_features() {
// Add your premium functionality here
add_action('init', array($this, 'init_premium_features'));
}
private function show_license_notice() {
add_action('admin_notices', function() {
?>
<div class="notice notice-warning">
<p>
<strong>My Awesome Plugin:</strong>
Please <a href="<?php echo admin_url('options-general.php?page=my-plugin-settings'); ?>">
activate your license</a> to access premium features and receive updates.
</p>
</div>
<?php
});
}
}
API Reference
WPDD_Plugin_Updater Class
Requirements
- WordPress: 5.0 or higher
- PHP: 7.0 or higher
- Plugin Version Header: Your main plugin file must include a Version header
Constructor Parameters
new WPDD_Plugin_Updater($plugin_file, $license_key, $update_server, $args);
- $plugin_file (string) - Full path to your main plugin file (typically
__FILE__
) - $license_key (string) - The user's license key (can be empty string)
- $update_server (string) - URL to your store (e.g., 'https://your-store.com')
- $args (array) - Optional arguments:
add_settings_page
(bool) - Auto-create license settings page (default: false)
Methods
validate_license()
Validates the current license with the server.
$is_valid = $updater->validate_license();
// Returns: boolean
activate_license($license_key)
Activates a license key for the current site.
$result = $updater->activate_license('XXXX-XXXX-XXXX-XXXX');
// Returns: array with 'success', 'message', and additional data
deactivate_license()
Deactivates the current license from this site.
$result = $updater->deactivate_license();
// Returns: array with 'success' and 'message'
Repository Setup (For Store Owners)
1. Create Software Product
- Go to your WordPress admin → Digital Products → Add New Product
- Select "Software License" as product type
- Fill in the software licensing fields:
- Git Repository URL
- License settings (max activations, duration)
- Version information
2. Configure Git Webhook
Add the generated webhook URL to your repository settings. The system receives webhook notifications FROM your Git platform when releases are published:
Gitea:
- Go to Settings → Webhooks
- Add webhook with the URL from your product page
- Set Content-Type to
application/json
- Select "Release events" as the trigger
- Ensure webhook is active
GitHub:
- Go to Settings → Webhooks
- Add webhook with the URL from your product page
- Set Content-Type to
application/json
- Select "Releases" events (or "Just the push event" for tag-based releases)
GitLab:
- Go to Settings → Webhooks
- Add the webhook URL
- Select "Tag push events" or "Releases events"
3. Release Process
Option 1: Using Git Platform Releases (Recommended for Gitea/GitHub)
-
Create a release through your Git platform's web interface:
- Navigate to Releases section
- Click "Create Release" or "New Release"
- Set tag name (e.g.,
v1.2.0
) - Add release notes in the description
- Publish the release
-
The webhook automatically receives the release notification and:
- Detects the new version from the release
- Clones the repository at the specific tag
- Creates distribution packages (removes dev files, creates ZIP)
- Stores version info and changelog in the database
- Makes update available to customers with active licenses
Option 2: Using Git Tags (Alternative)
-
Create and push a git tag:
git tag -a v1.2.0 -m "Version 1.2.0" git push origin v1.2.0
-
The webhook receives the tag push notification and processes the release similarly
API Endpoints
License Validation
POST /wp-json/wpdd/v1/validate-license
Body: {
"license_key": "XXXX-XXXX-XXXX-XXXX",
"product_slug": "my-plugin",
"site_url": "https://example.com"
}
Update Check
GET /wp-json/wpdd/v1/check-update/my-plugin?license_key=XXXX&version=1.0.0
Download Update
GET /wp-json/wpdd/v1/download-update/my-plugin?license_key=XXXX
Testing Your Integration
1. Local Testing
// Add this to your plugin for testing
if (defined('WP_DEBUG') && WP_DEBUG) {
add_action('admin_notices', function() {
$license_key = get_option('my_plugin_license_key', '');
$updater = new WPDD_Plugin_Updater(__FILE__, $license_key, 'https://your-store.com');
$is_valid = $updater->validate_license();
echo '<div class="notice notice-info">';
echo '<p>License Status: ' . ($is_valid ? 'Valid' : 'Invalid') . '</p>';
echo '</div>';
});
}
2. Force Update Check
// Add this temporarily to force update check
add_action('admin_init', function() {
if (isset($_GET['force_update_check'])) {
delete_transient('wpdd_update_my-plugin');
delete_site_transient('update_plugins');
wp_redirect(admin_url('plugins.php'));
exit;
}
});
Then visit: wp-admin/plugins.php?force_update_check=1
Best Practices
1. Error Handling
Always handle API failures gracefully:
// Check if updater was initialized properly
if (!$this->updater) {
// Handle initialization failure
error_log('WPDD Updater failed to initialize');
return;
}
$result = $updater->validate_license();
if ($result === false) {
// Network error or server down - allow functionality to continue
// but maybe show a notice
error_log('License validation failed - network or server issue');
}
2. Caching
The updater automatically caches responses. Don't call validation on every page load:
// Good - check once per day
$last_check = get_option('my_plugin_license_check', 0);
if (time() - $last_check > DAY_IN_SECONDS) {
$is_valid = $updater->validate_license();
update_option('my_plugin_license_check', time());
update_option('my_plugin_license_valid', $is_valid);
} else {
$is_valid = get_option('my_plugin_license_valid', false);
}
3. Graceful Degradation
Design your plugin to work without a valid license, but with reduced functionality:
if ($this->is_license_valid()) {
// Full functionality
$this->enable_all_features();
} else {
// Basic functionality only
$this->enable_basic_features();
$this->show_upgrade_notice();
}
What's New in Version 1.1.0
The updated wpdd-plugin-updater.php
includes several improvements:
Enhanced Error Handling
- Better HTTP request error handling with status code checking
- JSON validation to prevent parsing errors
- Improved timeout handling (30 seconds default)
- More detailed error logging for debugging
Improved Compatibility
- Better API response structure handling
- Flexible URL checking for package downloads
- Support for different server configurations
- Fallback values for missing data fields
Security Enhancements
- SSL verification enabled by default
- Proper input validation in constructor
- Safe handling of network failures
Performance Improvements
- 12-hour caching for update checks
- Optimized HTTP requests with proper headers
- Reduced unnecessary API calls
Troubleshooting
Common Issues
-
Updates not showing:
- Check that the plugin slug matches the product slug in your store
- Verify the plugin file has a proper Version header
- Clear update transients using the force update check method
-
License validation fails:
- Ensure the update server URL is correct and accessible
- Check that the license key is properly formatted
- Verify SSL certificates are valid on your server
-
Download fails:
- Verify the license is activated and not expired
- Check activation limits haven't been exceeded
- Ensure the package file exists on the server
Debug Mode
Enable WordPress debug logging and check for WPDD Updater messages:
// wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
Check /wp-content/debug.log
for error messages.
Support
For integration support:
- Check the troubleshooting section above
- Enable debug logging and check for error messages
- Contact support with your store URL and plugin details
Example Files
Complete example plugins are available in the /examples/
directory of this package.