Adding more functionality
This commit is contained in:
471
includes/wpdd-plugin-updater.php
Normal file
471
includes/wpdd-plugin-updater.php
Normal file
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
/**
|
||||
* WPDD Plugin Updater Library
|
||||
*
|
||||
* Include this file in your WordPress plugin to enable automatic updates
|
||||
* and license validation through the WP Digital Download licensing system.
|
||||
*
|
||||
* @version 1.0.0
|
||||
* @author WP Digital Download
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!class_exists('WPDD_Plugin_Updater')) {
|
||||
|
||||
class WPDD_Plugin_Updater {
|
||||
|
||||
private $plugin_slug;
|
||||
private $plugin_file;
|
||||
private $version;
|
||||
private $license_key;
|
||||
private $update_server;
|
||||
private $transient_key;
|
||||
|
||||
/**
|
||||
* Initialize the updater
|
||||
*
|
||||
* @param string $plugin_file Full path to the main plugin file
|
||||
* @param string $license_key Your license key
|
||||
* @param string $update_server URL to your update server
|
||||
* @param array $args Additional arguments
|
||||
*/
|
||||
public function __construct($plugin_file, $license_key, $update_server, $args = array()) {
|
||||
$this->plugin_file = $plugin_file;
|
||||
$this->plugin_slug = basename($plugin_file, '.php');
|
||||
$this->license_key = $license_key;
|
||||
$this->update_server = trailingslashit($update_server);
|
||||
|
||||
// Get plugin version from header
|
||||
if (!function_exists('get_plugin_data')) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
$plugin_data = get_plugin_data($plugin_file);
|
||||
$this->version = $plugin_data['Version'];
|
||||
|
||||
$this->transient_key = 'wpdd_update_' . $this->plugin_slug;
|
||||
|
||||
// Initialize hooks
|
||||
$this->init_hooks();
|
||||
|
||||
// Add settings page if requested
|
||||
if (isset($args['add_settings_page']) && $args['add_settings_page']) {
|
||||
$this->add_settings_page();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize WordPress hooks
|
||||
*/
|
||||
private function init_hooks() {
|
||||
add_filter('pre_set_site_transient_update_plugins', array($this, 'check_for_update'));
|
||||
add_filter('plugins_api', array($this, 'plugin_info'), 10, 3);
|
||||
add_filter('upgrader_pre_download', array($this, 'maybe_download_package'), 10, 3);
|
||||
|
||||
// Clean up transients on plugin activation/deactivation
|
||||
register_activation_hook($this->plugin_file, array($this, 'delete_transients'));
|
||||
register_deactivation_hook($this->plugin_file, array($this, 'delete_transients'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for plugin updates
|
||||
*/
|
||||
public function check_for_update($transient) {
|
||||
if (empty($transient->checked)) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
// Get cached update info
|
||||
$update_cache = get_transient($this->transient_key);
|
||||
if ($update_cache !== false) {
|
||||
if (isset($update_cache->update_available) && $update_cache->update_available) {
|
||||
$transient->response[$this->plugin_file] = $update_cache;
|
||||
}
|
||||
return $transient;
|
||||
}
|
||||
|
||||
// Check for update from server
|
||||
$update_info = $this->request_update_info();
|
||||
|
||||
if ($update_info && isset($update_info['update_available']) && $update_info['update_available']) {
|
||||
$plugin_data = array(
|
||||
'slug' => $this->plugin_slug,
|
||||
'plugin' => $this->plugin_file,
|
||||
'new_version' => $update_info['version'],
|
||||
'url' => $update_info['url'],
|
||||
'package' => $update_info['package'],
|
||||
'tested' => $update_info['tested'],
|
||||
'requires' => $update_info['requires'],
|
||||
'requires_php' => $update_info['requires_php'],
|
||||
'compatibility' => new stdClass()
|
||||
);
|
||||
|
||||
$update_cache = (object) $plugin_data;
|
||||
$update_cache->update_available = true;
|
||||
|
||||
// Cache for 12 hours
|
||||
set_transient($this->transient_key, $update_cache, 12 * HOUR_IN_SECONDS);
|
||||
|
||||
$transient->response[$this->plugin_file] = $update_cache;
|
||||
} else {
|
||||
// No update available - cache negative result for 12 hours
|
||||
$update_cache = new stdClass();
|
||||
$update_cache->update_available = false;
|
||||
set_transient($this->transient_key, $update_cache, 12 * HOUR_IN_SECONDS);
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide plugin information for the update screen
|
||||
*/
|
||||
public function plugin_info($false, $action, $args) {
|
||||
if ($action !== 'plugin_information' || $args->slug !== $this->plugin_slug) {
|
||||
return $false;
|
||||
}
|
||||
|
||||
$update_info = $this->request_update_info();
|
||||
|
||||
if (!$update_info) {
|
||||
return $false;
|
||||
}
|
||||
|
||||
return (object) array(
|
||||
'slug' => $this->plugin_slug,
|
||||
'name' => $update_info['name'] ?? $this->plugin_slug,
|
||||
'version' => $update_info['version'] ?? $this->version,
|
||||
'author' => $update_info['author'] ?? '',
|
||||
'homepage' => $update_info['url'] ?? '',
|
||||
'requires' => $update_info['requires'] ?? '5.0',
|
||||
'tested' => $update_info['tested'] ?? get_bloginfo('version'),
|
||||
'requires_php' => $update_info['requires_php'] ?? '7.0',
|
||||
'download_link' => $update_info['package'] ?? '',
|
||||
'sections' => array(
|
||||
'changelog' => $update_info['changelog'] ?? '',
|
||||
'description' => $update_info['description'] ?? ''
|
||||
),
|
||||
'banners' => array(),
|
||||
'icons' => array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle package download with license validation
|
||||
*/
|
||||
public function maybe_download_package($reply, $package, $upgrader) {
|
||||
// Check if this is our plugin's package
|
||||
if (strpos($package, $this->update_server) === false || strpos($package, $this->plugin_slug) === false) {
|
||||
return $reply;
|
||||
}
|
||||
|
||||
// Validate license before download
|
||||
$license_valid = $this->validate_license();
|
||||
if (!$license_valid) {
|
||||
return new WP_Error('license_invalid', __('Your license key is invalid or expired. Please update your license key.'));
|
||||
}
|
||||
|
||||
return $reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request update information from server
|
||||
*/
|
||||
private function request_update_info() {
|
||||
$url = $this->update_server . "wp-json/wpdd/v1/check-update/{$this->plugin_slug}";
|
||||
$url = add_query_arg(array(
|
||||
'license_key' => $this->license_key,
|
||||
'version' => $this->version,
|
||||
'site_url' => home_url()
|
||||
), $url);
|
||||
|
||||
$response = wp_remote_get($url, array(
|
||||
'timeout' => 15,
|
||||
'headers' => array(
|
||||
'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url()
|
||||
)
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
error_log('WPDD Updater: Failed to check for updates - ' . $response->get_error_message());
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (!$data || !isset($data['success'])) {
|
||||
error_log('WPDD Updater: Invalid response from update server');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$data['success']) {
|
||||
if (isset($data['error'])) {
|
||||
error_log('WPDD Updater: ' . $data['error'] . ' - ' . ($data['message'] ?? ''));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate license with server
|
||||
*/
|
||||
public function validate_license() {
|
||||
if (empty($this->license_key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$url = $this->update_server . 'wp-json/wpdd/v1/validate-license';
|
||||
|
||||
$response = wp_remote_post($url, array(
|
||||
'timeout' => 15,
|
||||
'body' => array(
|
||||
'license_key' => $this->license_key,
|
||||
'product_slug' => $this->plugin_slug,
|
||||
'site_url' => home_url()
|
||||
),
|
||||
'headers' => array(
|
||||
'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url()
|
||||
)
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
return $data && isset($data['success']) && $data['success'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate license
|
||||
*/
|
||||
public function activate_license($license_key = null) {
|
||||
if ($license_key) {
|
||||
$this->license_key = $license_key;
|
||||
}
|
||||
|
||||
if (empty($this->license_key)) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __('Please enter a license key.')
|
||||
);
|
||||
}
|
||||
|
||||
$url = $this->update_server . 'wp-json/wpdd/v1/activate-license';
|
||||
|
||||
$response = wp_remote_post($url, array(
|
||||
'timeout' => 15,
|
||||
'body' => array(
|
||||
'license_key' => $this->license_key,
|
||||
'site_url' => home_url(),
|
||||
'site_name' => get_bloginfo('name'),
|
||||
'wp_version' => get_bloginfo('version'),
|
||||
'php_version' => PHP_VERSION
|
||||
),
|
||||
'headers' => array(
|
||||
'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url()
|
||||
)
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => $response->get_error_message()
|
||||
);
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (!$data) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __('Invalid response from server.')
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivate license
|
||||
*/
|
||||
public function deactivate_license() {
|
||||
if (empty($this->license_key)) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => __('No license key to deactivate.')
|
||||
);
|
||||
}
|
||||
|
||||
$url = $this->update_server . 'wp-json/wpdd/v1/deactivate-license';
|
||||
|
||||
$response = wp_remote_post($url, array(
|
||||
'timeout' => 15,
|
||||
'body' => array(
|
||||
'license_key' => $this->license_key,
|
||||
'site_url' => home_url()
|
||||
),
|
||||
'headers' => array(
|
||||
'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url()
|
||||
)
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => $response->get_error_message()
|
||||
);
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
return $data ?: array(
|
||||
'success' => false,
|
||||
'message' => __('Invalid response from server.')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a simple settings page for license management
|
||||
*/
|
||||
private function add_settings_page() {
|
||||
add_action('admin_menu', array($this, 'add_license_menu'));
|
||||
add_action('admin_init', array($this, 'handle_license_actions'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add license menu page
|
||||
*/
|
||||
public function add_license_menu() {
|
||||
add_options_page(
|
||||
sprintf(__('%s License', 'default'), $this->plugin_slug),
|
||||
sprintf(__('%s License', 'default'), $this->plugin_slug),
|
||||
'manage_options',
|
||||
$this->plugin_slug . '-license',
|
||||
array($this, 'render_license_page')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle license activation/deactivation
|
||||
*/
|
||||
public function handle_license_actions() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$option_key = $this->plugin_slug . '_license_key';
|
||||
|
||||
if (isset($_POST['activate_license'])) {
|
||||
if (!wp_verify_nonce($_POST['license_nonce'], 'wpdd_license_nonce')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$license_key = sanitize_text_field($_POST['license_key']);
|
||||
$result = $this->activate_license($license_key);
|
||||
|
||||
if ($result['success']) {
|
||||
update_option($option_key, $license_key);
|
||||
$this->license_key = $license_key;
|
||||
add_settings_error('wpdd_license', 'activated', $result['message'], 'updated');
|
||||
} else {
|
||||
add_settings_error('wpdd_license', 'activation_failed', $result['message'], 'error');
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['deactivate_license'])) {
|
||||
if (!wp_verify_nonce($_POST['license_nonce'], 'wpdd_license_nonce')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = $this->deactivate_license();
|
||||
|
||||
if ($result['success']) {
|
||||
delete_option($option_key);
|
||||
$this->license_key = '';
|
||||
add_settings_error('wpdd_license', 'deactivated', $result['message'], 'updated');
|
||||
} else {
|
||||
add_settings_error('wpdd_license', 'deactivation_failed', $result['message'], 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render license management page
|
||||
*/
|
||||
public function render_license_page() {
|
||||
$option_key = $this->plugin_slug . '_license_key';
|
||||
$license_key = get_option($option_key, '');
|
||||
$license_status = $this->validate_license();
|
||||
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1><?php printf(__('%s License Settings', 'default'), esc_html($this->plugin_slug)); ?></h1>
|
||||
|
||||
<?php settings_errors('wpdd_license'); ?>
|
||||
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('wpdd_license_nonce', 'license_nonce'); ?>
|
||||
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="license_key"><?php _e('License Key', 'default'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" id="license_key" name="license_key"
|
||||
value="<?php echo esc_attr($license_key); ?>" class="regular-text" />
|
||||
|
||||
<?php if ($license_status): ?>
|
||||
<span class="dashicons dashicons-yes-alt" style="color: green;"></span>
|
||||
<span style="color: green;"><?php _e('Active', 'default'); ?></span>
|
||||
<?php elseif (!empty($license_key)): ?>
|
||||
<span class="dashicons dashicons-dismiss" style="color: red;"></span>
|
||||
<span style="color: red;"><?php _e('Invalid/Expired', 'default'); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<?php if (empty($license_key) || !$license_status): ?>
|
||||
<p class="submit">
|
||||
<input type="submit" name="activate_license" class="button-primary"
|
||||
value="<?php _e('Activate License', 'default'); ?>" />
|
||||
</p>
|
||||
<?php else: ?>
|
||||
<p class="submit">
|
||||
<input type="submit" name="deactivate_license" class="button-secondary"
|
||||
value="<?php _e('Deactivate License', 'default'); ?>" />
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<h2><?php _e('Instructions', 'default'); ?></h2>
|
||||
<ol>
|
||||
<li><?php _e('Enter your license key above and click "Activate License"', 'default'); ?></li>
|
||||
<li><?php _e('Once activated, you will receive automatic updates for this plugin', 'default'); ?></li>
|
||||
<li><?php _e('You can deactivate the license if you want to use it on a different site', 'default'); ?></li>
|
||||
</ol>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete update transients
|
||||
*/
|
||||
public function delete_transients() {
|
||||
delete_transient($this->transient_key);
|
||||
delete_site_transient('update_plugins');
|
||||
}
|
||||
}
|
||||
|
||||
} // End class exists check
|
Reference in New Issue
Block a user