Ansico-plugins/ansico-plugins/includes/class-ansico-plugins-updater.php

308 lines
14 KiB
PHP
Raw Permalink Normal View History

2026-04-18 20:50:31 +00:00
<?php
if (!defined('ABSPATH')) {
exit;
}
class Ansico_Plugins_Updater {
public function __construct() {
add_filter('pre_set_site_transient_update_plugins', array($this, 'inject_update_data'));
add_filter('plugins_api', array($this, 'plugins_api'), 20, 3);
add_filter('http_request_args', array($this, 'inject_auth_header'), 10, 2);
}
public function inject_update_data($transient) {
if (!is_object($transient)) {
$transient = new stdClass();
}
if (empty($transient->checked) || !is_array($transient->checked)) {
return $transient;
}
$managed_plugins = Ansico_Plugins::get_managed_plugins();
if (empty($managed_plugins)) {
return $transient;
}
if (!isset($transient->response) || !is_array($transient->response)) {
$transient->response = array();
}
if (!isset($transient->no_update) || !is_array($transient->no_update)) {
$transient->no_update = array();
}
$client = new Ansico_Plugins_Client();
foreach ($managed_plugins as $plugin_file => $meta) {
if (empty($transient->checked[$plugin_file])) {
continue;
}
$owner = !empty($meta['owner']) ? $meta['owner'] : '';
$repo = !empty($meta['repo']) ? $meta['repo'] : '';
if ('' === $owner || '' === $repo) {
continue;
}
$release = $client->get_latest_release($owner, $repo);
if (is_wp_error($release)) {
continue;
}
$zip_asset = $client->find_zip_asset($release);
if (!$zip_asset || empty($zip_asset['browser_download_url'])) {
continue;
}
$remote_version = $this->normalize_version($release);
$current_version = (string) $transient->checked[$plugin_file];
$plugin_data = $this->get_plugin_header($plugin_file);
$slug = !empty($meta['slug']) ? $meta['slug'] : dirname($plugin_file);
$item = (object) array(
'id' => $plugin_file,
'slug' => $slug,
'plugin' => $plugin_file,
'new_version' => $remote_version,
'url' => !empty($meta['repo_html_url']) ? $meta['repo_html_url'] : '',
'package' => $zip_asset['browser_download_url'],
'icons' => array(),
'banners' => array(),
'banners_rtl' => array(),
'tested' => !empty($plugin_data['RequiresWP']) ? $plugin_data['RequiresWP'] : '',
'requires_php' => !empty($plugin_data['RequiresPHP']) ? $plugin_data['RequiresPHP'] : '',
'compatibility' => new stdClass(),
);
if (version_compare($remote_version, $current_version, '>')) {
$transient->response[$plugin_file] = $item;
unset($transient->no_update[$plugin_file]);
} else {
$transient->no_update[$plugin_file] = $item;
unset($transient->response[$plugin_file]);
}
}
$transient = $this->inject_self_update_data($transient, $client);
return $transient;
}
public function plugins_api($result, $action, $args) {
if ('plugin_information' !== $action || empty($args->slug)) {
return $result;
}
$client = new Ansico_Plugins_Client();
if ($this->is_self_plugin_slug($args->slug)) {
$self_info = $this->get_self_update_info($client);
if (!$self_info) {
return $result;
}
$sections = array(
'description' => !empty($self_info['repo_meta']['plugin_headers']['Description']) ? wp_kses_post(wpautop($self_info['repo_meta']['plugin_headers']['Description'])) : wp_kses_post(wpautop(__('Ansico Plugins forbinder WordPress med private Forgejo-hostede plugins.', 'ansico-plugins'))),
'installation' => wp_kses_post(wpautop(__('Installeres manuelt første gang. Derefter kan pluginet opdatere sig selv via Forgejo releases.', 'ansico-plugins'))),
'changelog' => !empty($self_info['release']['body']) ? wp_kses_post(wpautop($self_info['release']['body'])) : wp_kses_post(wpautop(__('Ingen changelog tilgængelig.', 'ansico-plugins'))),
);
return (object) array(
'name' => !empty($self_info['repo_meta']['readme_title']) ? $self_info['repo_meta']['readme_title'] : 'Ansico Plugins',
'slug' => dirname(plugin_basename(ANSICO_PLUGINS_FILE)),
'version' => $this->normalize_version($self_info['release']),
'author' => !empty($self_info['repo_meta']['author_name']) ? '<a href="' . esc_url(!empty($self_info['repo_meta']['author_url']) ? $self_info['repo_meta']['author_url'] : 'https://ansico.dk') . '">' . esc_html($self_info['repo_meta']['author_name']) . '</a>' : '<a href="https://ansico.dk">Andreas Andersen (Ansico)</a>',
'author_profile' => !empty($self_info['repo_meta']['author_url']) ? $self_info['repo_meta']['author_url'] : 'https://ansico.dk',
'homepage' => !empty($self_info['repo']['html_url']) ? $self_info['repo']['html_url'] : '',
'requires' => !empty($self_info['plugin_data']['RequiresWP']) ? $self_info['plugin_data']['RequiresWP'] : '',
'requires_php' => !empty($self_info['plugin_data']['RequiresPHP']) ? $self_info['plugin_data']['RequiresPHP'] : '',
'tested' => get_bloginfo('version'),
'last_updated' => !empty($self_info['release']['published_at']) ? gmdate('Y-m-d', strtotime($self_info['release']['published_at'])) : '',
'download_link' => (!empty($self_info['zip_asset']['browser_download_url'])) ? $self_info['zip_asset']['browser_download_url'] : '',
'sections' => $sections,
'banners' => array(),
'icons' => !empty($self_info['repo_meta']['screenshot_url']) ? array('default' => $self_info['repo_meta']['screenshot_url']) : array(),
'external' => true,
);
}
$managed_plugins = Ansico_Plugins::get_managed_plugins();
if (empty($managed_plugins)) {
return $result;
}
$matched = null;
foreach ($managed_plugins as $plugin_file => $meta) {
if (!empty($meta['slug']) && $meta['slug'] === $args->slug) {
$matched = array('plugin_file' => $plugin_file, 'meta' => $meta);
break;
}
}
if (!$matched) {
return $result;
}
$release = $client->get_latest_release($matched['meta']['owner'], $matched['meta']['repo']);
if (is_wp_error($release)) {
return $result;
}
$zip_asset = $client->find_zip_asset($release);
$plugin_data = $this->get_plugin_header($matched['plugin_file']);
$repo_meta = $client->get_repository_plugin_metadata($matched['meta']['owner'], $matched['meta']['repo']);
$repo_meta = is_wp_error($repo_meta) ? array() : $repo_meta;
$sections = array(
'description' => !empty($matched['meta']['description']) ? wp_kses_post(wpautop($matched['meta']['description'])) : wp_kses_post(wpautop(__('Privat plugin distribueret via Forgejo.', 'ansico-plugins'))),
'installation' => wp_kses_post(wpautop(__('Installeres og opdateres via Ansico Plugins og Forgejo releases.', 'ansico-plugins'))),
'changelog' => !empty($release['body']) ? wp_kses_post(wpautop($release['body'])) : wp_kses_post(wpautop(__('Ingen changelog tilgængelig.', 'ansico-plugins'))),
);
return (object) array(
'name' => !empty($plugin_data['Name']) ? $plugin_data['Name'] : $matched['meta']['repo'],
'slug' => $matched['meta']['slug'],
'version' => $this->normalize_version($release),
'author' => !empty($repo_meta['author_name']) ? '<a href="' . esc_url(!empty($repo_meta['author_url']) ? $repo_meta['author_url'] : 'https://ansico.dk') . '">' . esc_html($repo_meta['author_name']) . '</a>' : '<a href="https://ansico.dk">Andreas Andersen (Ansico)</a>',
'author_profile' => !empty($repo_meta['author_url']) ? $repo_meta['author_url'] : 'https://ansico.dk',
'homepage' => !empty($matched['meta']['repo_html_url']) ? $matched['meta']['repo_html_url'] : '',
'requires' => !empty($plugin_data['RequiresWP']) ? $plugin_data['RequiresWP'] : '',
'requires_php' => !empty($plugin_data['RequiresPHP']) ? $plugin_data['RequiresPHP'] : '',
'tested' => get_bloginfo('version'),
'last_updated' => !empty($release['published_at']) ? gmdate('Y-m-d', strtotime($release['published_at'])) : '',
'download_link' => $zip_asset ? $zip_asset['browser_download_url'] : '',
'sections' => $sections,
'banners' => array(),
'icons' => !empty($repo_meta['screenshot_url']) ? array('default' => $repo_meta['screenshot_url']) : array(),
'external' => true,
);
}
private function inject_self_update_data($transient, $client) {
$settings = Ansico_Plugins::get_settings();
if (empty($settings['self_update_enabled']) || empty($settings['self_update_owner']) || empty($settings['self_update_repo'])) {
return $transient;
}
$plugin_file = plugin_basename(ANSICO_PLUGINS_FILE);
if (empty($transient->checked[$plugin_file])) {
return $transient;
}
$release = $client->get_latest_release($settings['self_update_owner'], $settings['self_update_repo']);
if (is_wp_error($release)) {
return $transient;
}
$zip_asset = $client->find_zip_asset($release);
if (!$zip_asset || empty($zip_asset['browser_download_url'])) {
return $transient;
}
$remote_version = $this->normalize_version($release);
$current_version = (string) $transient->checked[$plugin_file];
$repo = $client->get_repository($settings['self_update_owner'], $settings['self_update_repo']);
$repo_url = (!is_wp_error($repo) && !empty($repo['html_url'])) ? (string) $repo['html_url'] : '';
$item = (object) array(
'id' => $plugin_file,
'slug' => dirname($plugin_file),
'plugin' => $plugin_file,
'new_version' => $remote_version,
'url' => $repo_url,
'package' => $zip_asset['browser_download_url'],
'icons' => array(),
'banners' => array(),
'banners_rtl' => array(),
'tested' => '',
'requires_php' => '',
'compatibility' => new stdClass(),
);
if (version_compare($remote_version, $current_version, '>')) {
$transient->response[$plugin_file] = $item;
unset($transient->no_update[$plugin_file]);
} else {
$transient->no_update[$plugin_file] = $item;
unset($transient->response[$plugin_file]);
}
return $transient;
}
private function is_self_plugin_slug($slug) {
return in_array((string) $slug, array('ansico-plugins', dirname(plugin_basename(ANSICO_PLUGINS_FILE))), true);
}
private function get_self_update_info($client) {
$settings = Ansico_Plugins::get_settings();
if (empty($settings['self_update_enabled']) || empty($settings['self_update_owner']) || empty($settings['self_update_repo'])) {
return null;
}
$release = $client->get_latest_release($settings['self_update_owner'], $settings['self_update_repo']);
if (is_wp_error($release)) {
return null;
}
$repo = $client->get_repository($settings['self_update_owner'], $settings['self_update_repo']);
$repo_meta = $client->get_repository_plugin_metadata($settings['self_update_owner'], $settings['self_update_repo']);
$zip_asset = $client->find_zip_asset($release);
$plugin_data = $this->get_plugin_header(plugin_basename(ANSICO_PLUGINS_FILE));
return array(
'settings' => $settings,
'release' => $release,
'repo' => is_wp_error($repo) ? array() : $repo,
'repo_meta' => is_wp_error($repo_meta) ? array() : $repo_meta,
'zip_asset' => $zip_asset,
'plugin_data' => $plugin_data,
);
}
public function inject_auth_header($args, $url) {
$settings = Ansico_Plugins::get_settings();
$base = trailingslashit($settings['forgejo_base_url']);
if (empty($settings['access_token']) || empty($base) || strpos($url, $base) !== 0) {
return $args;
}
if (empty($args['headers']) || !is_array($args['headers'])) {
$args['headers'] = array();
}
$args['headers']['Authorization'] = 'token ' . trim((string) $settings['access_token']);
$args['sslverify'] = !empty($settings['verify_ssl']);
return $args;
}
private function normalize_version($release) {
$version = '';
if (!empty($release['tag_name'])) {
$version = (string) $release['tag_name'];
} elseif (!empty($release['name'])) {
$version = (string) $release['name'];
}
$version = ltrim($version, 'vV');
return '' !== $version ? $version : '0.0.0';
}
private function get_plugin_header($plugin_file) {
if (!function_exists('get_plugin_data')) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$path = WP_PLUGIN_DIR . '/' . ltrim($plugin_file, '/');
if (!file_exists($path)) {
return array();
}
return get_plugin_data($path, false, false);
}
}