feat/fix: checkout email tracing, UI tweaks for add-to-cart, cart page overflow fix, implement hide admin bar setting
This commit is contained in:
391
templates/updater/class-woonoow-updater.php
Normal file
391
templates/updater/class-woonoow-updater.php
Normal file
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* WooNooW Software Updater
|
||||
*
|
||||
* Embed this class in your WordPress plugin or theme to enable
|
||||
* automatic updates from your WooNooW-powered store.
|
||||
*
|
||||
* @version 1.0.0
|
||||
* @package WooNooW_Updater
|
||||
* @link https://woonoow.com/docs/developer/software-updates
|
||||
*
|
||||
* USAGE:
|
||||
*
|
||||
* 1. Copy this file to your plugin/theme (e.g., includes/class-woonoow-updater.php)
|
||||
*
|
||||
* 2. Include and initialize in your main plugin file:
|
||||
*
|
||||
* require_once plugin_dir_path(__FILE__) . 'includes/class-woonoow-updater.php';
|
||||
*
|
||||
* new WooNooW_Updater([
|
||||
* 'api_url' => 'https://your-store.com/',
|
||||
* 'slug' => 'my-plugin',
|
||||
* 'version' => MY_PLUGIN_VERSION,
|
||||
* 'license_key' => get_option('my_plugin_license_key'),
|
||||
* 'plugin_file' => __FILE__, // For plugins
|
||||
* // OR
|
||||
* 'theme_slug' => 'my-theme', // For themes
|
||||
* ]);
|
||||
*/
|
||||
|
||||
if (!class_exists('WooNooW_Updater')) {
|
||||
|
||||
class WooNooW_Updater
|
||||
{
|
||||
/**
|
||||
* @var string API base URL
|
||||
*/
|
||||
private $api_url;
|
||||
|
||||
/**
|
||||
* @var string Software slug
|
||||
*/
|
||||
private $slug;
|
||||
|
||||
/**
|
||||
* @var string Plugin file path (for plugins)
|
||||
*/
|
||||
private $plugin_file;
|
||||
|
||||
/**
|
||||
* @var string Theme slug (for themes)
|
||||
*/
|
||||
private $theme_slug;
|
||||
|
||||
/**
|
||||
* @var string Current version
|
||||
*/
|
||||
private $version;
|
||||
|
||||
/**
|
||||
* @var string License key
|
||||
*/
|
||||
private $license_key;
|
||||
|
||||
/**
|
||||
* @var string Cache key for transient
|
||||
*/
|
||||
private $cache_key;
|
||||
|
||||
/**
|
||||
* @var int Cache TTL in seconds (default: 12 hours)
|
||||
*/
|
||||
private $cache_ttl = 43200;
|
||||
|
||||
/**
|
||||
* @var bool Is this a theme update?
|
||||
*/
|
||||
private $is_theme = false;
|
||||
|
||||
/**
|
||||
* Initialize the updater
|
||||
*
|
||||
* @param array $config Configuration array
|
||||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
$this->api_url = trailingslashit($config['api_url'] ?? '');
|
||||
$this->slug = $config['slug'] ?? '';
|
||||
$this->version = $config['version'] ?? '1.0.0';
|
||||
$this->license_key = $config['license_key'] ?? '';
|
||||
$this->cache_key = 'woonoow_update_' . md5($this->slug);
|
||||
|
||||
// Determine if plugin or theme
|
||||
if (!empty($config['theme_slug'])) {
|
||||
$this->is_theme = true;
|
||||
$this->theme_slug = $config['theme_slug'];
|
||||
} else {
|
||||
$this->plugin_file = $config['plugin_file'] ?? '';
|
||||
}
|
||||
|
||||
// Set cache TTL if provided
|
||||
if (!empty($config['cache_ttl'])) {
|
||||
$this->cache_ttl = (int) $config['cache_ttl'] * 3600; // Convert hours to seconds
|
||||
}
|
||||
|
||||
// Don't proceed if no API URL or license
|
||||
if (empty($this->api_url) || empty($this->slug)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hook into WordPress update system
|
||||
if ($this->is_theme) {
|
||||
add_filter('pre_set_site_transient_update_themes', [$this, 'check_theme_update']);
|
||||
add_filter('themes_api', [$this, 'theme_info'], 20, 3);
|
||||
} else {
|
||||
add_filter('pre_set_site_transient_update_plugins', [$this, 'check_plugin_update']);
|
||||
add_filter('plugins_api', [$this, 'plugin_info'], 20, 3);
|
||||
}
|
||||
|
||||
// Clear cache on upgrade
|
||||
add_action('upgrader_process_complete', [$this, 'clear_cache'], 10, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for plugin updates
|
||||
*
|
||||
* @param object $transient Update transient
|
||||
* @return object Modified transient
|
||||
*/
|
||||
public function check_plugin_update($transient)
|
||||
{
|
||||
if (empty($transient->checked)) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$remote = $this->get_remote_info();
|
||||
|
||||
if ($remote && !empty($remote->latest_version)) {
|
||||
if (version_compare($this->version, $remote->latest_version, '<')) {
|
||||
$plugin_file = plugin_basename($this->plugin_file);
|
||||
|
||||
$transient->response[$plugin_file] = (object) [
|
||||
'slug' => $this->slug,
|
||||
'plugin' => $plugin_file,
|
||||
'new_version' => $remote->latest_version,
|
||||
'package' => $remote->download_url ?? '',
|
||||
'url' => $remote->homepage ?? '',
|
||||
'tested' => $remote->wordpress->tested ?? '',
|
||||
'requires' => $remote->wordpress->requires ?? '',
|
||||
'requires_php' => $remote->wordpress->requires_php ?? '',
|
||||
'icons' => (array) ($remote->wordpress->icons ?? []),
|
||||
'banners' => (array) ($remote->wordpress->banners ?? []),
|
||||
];
|
||||
} else {
|
||||
// No update available
|
||||
$transient->no_update[plugin_basename($this->plugin_file)] = (object) [
|
||||
'slug' => $this->slug,
|
||||
'plugin' => plugin_basename($this->plugin_file),
|
||||
'new_version' => $this->version,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for theme updates
|
||||
*
|
||||
* @param object $transient Update transient
|
||||
* @return object Modified transient
|
||||
*/
|
||||
public function check_theme_update($transient)
|
||||
{
|
||||
if (empty($transient->checked)) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$remote = $this->get_remote_info();
|
||||
|
||||
if ($remote && !empty($remote->latest_version)) {
|
||||
if (version_compare($this->version, $remote->latest_version, '<')) {
|
||||
$transient->response[$this->theme_slug] = [
|
||||
'theme' => $this->theme_slug,
|
||||
'new_version' => $remote->latest_version,
|
||||
'package' => $remote->download_url ?? '',
|
||||
'url' => $remote->homepage ?? '',
|
||||
'requires' => $remote->wordpress->requires ?? '',
|
||||
'requires_php' => $remote->wordpress->requires_php ?? '',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide plugin information for details popup
|
||||
*
|
||||
* @param mixed $result Default result
|
||||
* @param string $action Action being performed
|
||||
* @param object $args Arguments
|
||||
* @return mixed Plugin info or default result
|
||||
*/
|
||||
public function plugin_info($result, $action, $args)
|
||||
{
|
||||
if ($action !== 'plugin_information' || !isset($args->slug) || $args->slug !== $this->slug) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$remote = $this->get_remote_info();
|
||||
|
||||
if (!$remote) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'name' => $remote->product->name ?? $this->slug,
|
||||
'slug' => $this->slug,
|
||||
'version' => $remote->latest_version,
|
||||
'tested' => $remote->wordpress->tested ?? '',
|
||||
'requires' => $remote->wordpress->requires ?? '',
|
||||
'requires_php' => $remote->wordpress->requires_php ?? '',
|
||||
'author' => $remote->author ?? '',
|
||||
'homepage' => $remote->homepage ?? '',
|
||||
'download_link' => $remote->download_url ?? '',
|
||||
'sections' => [
|
||||
'description' => $remote->description ?? '',
|
||||
'changelog' => nl2br($remote->changelog ?? ''),
|
||||
],
|
||||
'banners' => (array) ($remote->wordpress->banners ?? []),
|
||||
'icons' => (array) ($remote->wordpress->icons ?? []),
|
||||
'last_updated' => $remote->release_date ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide theme information for details popup
|
||||
*
|
||||
* @param mixed $result Default result
|
||||
* @param string $action Action being performed
|
||||
* @param object $args Arguments
|
||||
* @return mixed Theme info or default result
|
||||
*/
|
||||
public function theme_info($result, $action, $args)
|
||||
{
|
||||
if ($action !== 'theme_information' || !isset($args->slug) || $args->slug !== $this->theme_slug) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$remote = $this->get_remote_info();
|
||||
|
||||
if (!$remote) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'name' => $remote->product->name ?? $this->theme_slug,
|
||||
'slug' => $this->theme_slug,
|
||||
'version' => $remote->latest_version,
|
||||
'requires' => $remote->wordpress->requires ?? '',
|
||||
'requires_php' => $remote->wordpress->requires_php ?? '',
|
||||
'author' => $remote->author ?? '',
|
||||
'homepage' => $remote->homepage ?? '',
|
||||
'download_link' => $remote->download_url ?? '',
|
||||
'sections' => [
|
||||
'description' => $remote->description ?? '',
|
||||
'changelog' => nl2br($remote->changelog ?? ''),
|
||||
],
|
||||
'last_updated' => $remote->release_date ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote version info from API
|
||||
*
|
||||
* @return object|null Remote info or null on failure
|
||||
*/
|
||||
private function get_remote_info()
|
||||
{
|
||||
// Check cache first
|
||||
$cached = get_transient($this->cache_key);
|
||||
if ($cached !== false) {
|
||||
if ($cached === 'no_update') {
|
||||
return null;
|
||||
}
|
||||
return $cached;
|
||||
}
|
||||
|
||||
// Make API request
|
||||
$response = wp_remote_post($this->api_url . 'wp-json/woonoow/v1/software/check', [
|
||||
'timeout' => 15,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'body' => wp_json_encode([
|
||||
'license_key' => $this->license_key,
|
||||
'slug' => $this->slug,
|
||||
'version' => $this->version,
|
||||
'site_url' => home_url(),
|
||||
'wp_version' => get_bloginfo('version'),
|
||||
'php_version' => phpversion(),
|
||||
]),
|
||||
]);
|
||||
|
||||
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
|
||||
// Cache failure for shorter time to retry sooner
|
||||
set_transient($this->cache_key, 'no_update', 3600);
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_decode(wp_remote_retrieve_body($response));
|
||||
|
||||
if (!$data || empty($data->success)) {
|
||||
set_transient($this->cache_key, 'no_update', 3600);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (empty($data->update_available)) {
|
||||
set_transient($this->cache_key, 'no_update', $this->cache_ttl);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Cache the update info
|
||||
set_transient($this->cache_key, $data, $this->cache_ttl);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear update cache after upgrade
|
||||
*
|
||||
* @param object $upgrader Upgrader instance
|
||||
* @param array $options Upgrade options
|
||||
*/
|
||||
public function clear_cache($upgrader, $options)
|
||||
{
|
||||
if ($this->is_theme) {
|
||||
if ($options['action'] === 'update' && $options['type'] === 'theme') {
|
||||
if (isset($options['themes']) && in_array($this->theme_slug, $options['themes'])) {
|
||||
delete_transient($this->cache_key);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($options['action'] === 'update' && $options['type'] === 'plugin') {
|
||||
if (isset($options['plugins']) && in_array(plugin_basename($this->plugin_file), $options['plugins'])) {
|
||||
delete_transient($this->cache_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force check for updates (bypass cache)
|
||||
*/
|
||||
public function force_check()
|
||||
{
|
||||
delete_transient($this->cache_key);
|
||||
return $this->get_remote_info();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get license status
|
||||
*
|
||||
* @return array|null License status or null on failure
|
||||
*/
|
||||
public function get_license_status()
|
||||
{
|
||||
if (empty($this->license_key)) {
|
||||
return ['valid' => false, 'error' => 'no_license'];
|
||||
}
|
||||
|
||||
$response = wp_remote_post($this->api_url . 'wp-json/woonoow/v1/licenses/validate', [
|
||||
'timeout' => 15,
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
'body' => wp_json_encode([
|
||||
'license_key' => $this->license_key,
|
||||
]),
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return json_decode(wp_remote_retrieve_body($response), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user