Move 288 types from global AKSRT_* + inc/classes manual requires into
namespace AKSRT\{Domain} under src/AKSRT/, wire composer.json psr-4,
and slim bootstrap to helpers/modules/hooks only. Split multi-class
widget/gateway files, update admin contract audit paths, and document
the layout in ADR/README.
172 lines
5.1 KiB
PHP
172 lines
5.1 KiB
PHP
<?php
|
|
/**
|
|
* @package AKSRT
|
|
*/
|
|
|
|
namespace AKSRT\Core;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
class UpdateChecker {
|
|
|
|
private static $instance = null;
|
|
private const OPTION_KEY = 'aksrt_update_check';
|
|
private const CHECK_INTERVAL = DAY_IN_SECONDS * 1; // Check daily
|
|
|
|
private function __construct() {}
|
|
|
|
public static function get_instance(): self {
|
|
if (null === self::$instance) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
public function init(): void {
|
|
add_action('admin_init', [$this, 'maybe_check']);
|
|
add_action('admin_notices', [$this, 'show_update_notice']);
|
|
}
|
|
|
|
/**
|
|
* Get current theme version
|
|
*/
|
|
private function get_current_version(): string {
|
|
$theme = wp_get_theme();
|
|
return $theme->get('Version') ?: '0.0.0';
|
|
}
|
|
|
|
/**
|
|
* Get update endpoint URL
|
|
*/
|
|
private function get_endpoint(): string {
|
|
if (class_exists('\AKSRT\Settings\Settings')) {
|
|
$endpoint = \AKSRT\Settings\Settings::get_value('update_endpoint', '');
|
|
if (!empty($endpoint)) return $endpoint;
|
|
}
|
|
return 'https://api.aksrt.com/version.json';
|
|
}
|
|
|
|
/**
|
|
* Maybe check for updates (once per day)
|
|
*/
|
|
public function maybe_check(): void {
|
|
$stored = get_option(self::OPTION_KEY, []);
|
|
$last_check = $stored['last_check'] ?? 0;
|
|
|
|
if ((time() - $last_check) < self::CHECK_INTERVAL) {
|
|
return;
|
|
}
|
|
|
|
$this->do_check();
|
|
}
|
|
|
|
/**
|
|
* Force check for updates
|
|
*/
|
|
public function do_check(): void {
|
|
$endpoint = $this->get_endpoint();
|
|
|
|
$response = wp_remote_get($endpoint, [
|
|
'timeout' => 5,
|
|
'headers' => [
|
|
'Accept' => 'application/json',
|
|
],
|
|
]);
|
|
|
|
if (is_wp_error($response)) {
|
|
update_option(self::OPTION_KEY, [
|
|
'last_check' => time(),
|
|
'error' => $response->get_error_message(),
|
|
]);
|
|
return;
|
|
}
|
|
|
|
$body = wp_remote_retrieve_body($response);
|
|
$data = json_decode($body, true);
|
|
|
|
if (!is_array($data) || empty($data['version'])) {
|
|
return;
|
|
}
|
|
|
|
$current = $this->get_current_version();
|
|
$remote_version = $data['version'];
|
|
$update_available = version_compare($remote_version, $current, '>');
|
|
|
|
update_option(self::OPTION_KEY, [
|
|
'last_check' => time(),
|
|
'current_version' => $current,
|
|
'remote_version' => $remote_version,
|
|
'update_available' => $update_available,
|
|
'download_url' => $data['download_url'] ?? '',
|
|
'changelog' => $data['changelog'] ?? '',
|
|
'notify' => !empty($data['notify']),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Show admin notice if update is available
|
|
*/
|
|
public function show_update_notice(): void {
|
|
if (!current_user_can('update_themes')) return;
|
|
|
|
$stored = get_option(self::OPTION_KEY, []);
|
|
if (empty($stored['update_available'])) return;
|
|
|
|
$remote = $stored['remote_version'] ?? '';
|
|
$current = $stored['current_version'] ?? '';
|
|
$download_url = $stored['download_url'] ?? '';
|
|
$changelog = $stored['changelog'] ?? '';
|
|
|
|
// User dismissed this version?
|
|
$dismissed = get_user_meta(get_current_user_id(), 'aksrt_dismissed_update', true);
|
|
if ($dismissed === $remote) return;
|
|
|
|
$dismiss_url = wp_nonce_url(
|
|
add_query_arg('aksrt_dismiss_update', $remote, admin_url()),
|
|
'aksrt_dismiss_update_' . $remote
|
|
);
|
|
|
|
echo '<div class="notice notice-info is-dismissible">';
|
|
echo '<p><strong>' . esc_html__('AKSRT 主题更新', 'aksrt') . '</strong></p>';
|
|
echo '<p>' . sprintf(
|
|
esc_html__('新版本 %s 可用(当前版本 %s)。', 'aksrt'),
|
|
'<strong>' . esc_html($remote) . '</strong>',
|
|
esc_html($current)
|
|
) . '</p>';
|
|
|
|
if (!empty($changelog)) {
|
|
echo '<p>' . esc_html($changelog) . '</p>';
|
|
}
|
|
|
|
echo '<p>';
|
|
if (!empty($download_url)) {
|
|
echo '<a href="' . esc_url($download_url) . '" class="button button-primary" target="_blank">'
|
|
. esc_html__('下载更新', 'aksrt') . '</a> ';
|
|
}
|
|
echo '<a href="' . esc_url($dismiss_url) . '" class="button">'
|
|
. esc_html__('忽略此版本', 'aksrt') . '</a>';
|
|
echo '</p>';
|
|
echo '</div>';
|
|
}
|
|
|
|
/**
|
|
* Handle dismiss action
|
|
*/
|
|
public static function handle_dismiss(): void {
|
|
if (!isset($_GET['aksrt_dismiss_update'])) return;
|
|
$version = sanitize_text_field($_GET['aksrt_dismiss_update']);
|
|
if (!wp_verify_nonce($_GET['_wp_nonce'] ?? '', 'aksrt_dismiss_update_' . $version)) return;
|
|
|
|
update_user_meta(get_current_user_id(), 'aksrt_dismissed_update', $version);
|
|
wp_safe_redirect(remove_query_arg(['aksrt_dismiss_update', '_wp_nonce']));
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Get stored update info
|
|
*/
|
|
public function get_update_info(): array {
|
|
return get_option(self::OPTION_KEY, []);
|
|
}
|
|
}
|