feat: add GitHub-powered updates to WordPress admin
Build plugin release / release (push) Failing after 4s
Build plugin release / release (push) Failing after 4s
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Dabestaniha\AuthenticateBridge\App\Http\Controllers;
|
||||
|
||||
use Dabestaniha\AuthenticateBridge\App\Support\PluginUpdater;
|
||||
|
||||
class SettingsPageMenuController extends InvocableController
|
||||
{
|
||||
public function __invoke()
|
||||
@@ -27,7 +29,8 @@ class SettingsPageMenuController extends InvocableController
|
||||
submit_button();
|
||||
?>
|
||||
</form>
|
||||
<?php PluginUpdater::renderUpdatePanel(); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
namespace Dabestaniha\AuthenticateBridge\App\Support;
|
||||
|
||||
final class PluginUpdater
|
||||
{
|
||||
private const API_URL = 'https://api.github.com/repos/dabestaniha/mahak-authenticate-bridge/releases/latest';
|
||||
private const RELEASE_ASSET = 'mahak-authenticate-bridge.zip';
|
||||
private const RELEASE_CACHE = 'mahak_authenticate_bridge_release';
|
||||
private const CHECK_ACTION = 'mahak_authenticate_check_updates';
|
||||
|
||||
private static ?self $instance = null;
|
||||
|
||||
private string $plugin;
|
||||
private string $slug;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->plugin = plugin_basename(MAHAK_AUTHENTICATE_BRIDGE_FILE);
|
||||
$this->slug = dirname($this->plugin);
|
||||
}
|
||||
|
||||
public static function boot(): void
|
||||
{
|
||||
if (self::$instance !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$instance = new self();
|
||||
add_filter('pre_set_site_transient_update_plugins', [self::$instance, 'addUpdate']);
|
||||
add_filter('plugins_api', [self::$instance, 'addPluginInformation'], 20, 3);
|
||||
add_action('admin_post_'.self::CHECK_ACTION, [self::$instance, 'checkNow']);
|
||||
}
|
||||
|
||||
public function addUpdate($transient)
|
||||
{
|
||||
if (!is_object($transient) || empty($transient->checked)) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$update = $this->availableUpdate();
|
||||
|
||||
if ($update !== null) {
|
||||
if (!isset($transient->response) || !is_array($transient->response)) {
|
||||
$transient->response = [];
|
||||
}
|
||||
|
||||
$transient->response[$this->plugin] = $update;
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
public function addPluginInformation($result, string $action, $args)
|
||||
{
|
||||
if ($action !== 'plugin_information' || ($args->slug ?? '') !== $this->slug) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$release = $this->latestRelease();
|
||||
|
||||
if (is_wp_error($release)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$package = $this->releasePackage($release);
|
||||
|
||||
if ($package === null) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'name' => 'Mahak Authenticate Bridge',
|
||||
'slug' => $this->slug,
|
||||
'version' => $this->releaseVersion($release),
|
||||
'author' => 'Dabestaniha',
|
||||
'homepage' => $release['html_url'] ?? 'https://github.com/dabestaniha/mahak-authenticate-bridge',
|
||||
'download_link' => $package,
|
||||
'requires_php' => '7.4',
|
||||
'sections' => [
|
||||
'description' => 'Authenticate WordPress users via JSON Web Tokens from the Mahakiha application.',
|
||||
'changelog' => nl2br(esc_html((string) ($release['body'] ?? ''))),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function checkNow(): void
|
||||
{
|
||||
if (!current_user_can('update_plugins')) {
|
||||
wp_die(esc_html__('Sorry, you are not allowed to update plugins.'));
|
||||
}
|
||||
|
||||
check_admin_referer(self::CHECK_ACTION);
|
||||
delete_site_transient(self::RELEASE_CACHE);
|
||||
delete_site_transient('update_plugins');
|
||||
wp_update_plugins();
|
||||
|
||||
wp_safe_redirect(add_query_arg(
|
||||
['page' => config('mahak.settings-page'), 'update-checked' => '1'],
|
||||
admin_url('options-general.php')
|
||||
));
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function renderUpdatePanel(): void
|
||||
{
|
||||
if (self::$instance === null || !current_user_can('update_plugins')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$updater = self::$instance;
|
||||
$release = $updater->latestRelease();
|
||||
|
||||
echo '<hr><h2>'.esc_html__('Plugin updates').'</h2>';
|
||||
echo '<p>'.sprintf(
|
||||
esc_html__('Installed version: %s'),
|
||||
'<strong>'.esc_html(MAHAK_AUTHENTICATE_BRIDGE_VERSION).'</strong>'
|
||||
).'</p>';
|
||||
|
||||
if (is_wp_error($release)) {
|
||||
echo '<div class="notice notice-warning inline"><p>'.esc_html($release->get_error_message()).'</p></div>';
|
||||
} else {
|
||||
$update = $updater->availableUpdate($release);
|
||||
|
||||
if ($update !== null) {
|
||||
echo '<p>'.sprintf(esc_html__('Version %s is available.'), esc_html($update->new_version)).'</p>';
|
||||
$updateUrl = wp_nonce_url(
|
||||
self_admin_url('update.php?action=upgrade-plugin&plugin='.rawurlencode($updater->plugin)),
|
||||
'upgrade-plugin_'.$updater->plugin
|
||||
);
|
||||
echo '<p><a class="button button-primary" href="'.esc_url($updateUrl).'">'.esc_html__('Update now').'</a></p>';
|
||||
} else {
|
||||
echo '<p>'.esc_html__('You are using the latest available version.').'</p>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '<form method="post" action="'.esc_url(admin_url('admin-post.php')).'">';
|
||||
echo '<input type="hidden" name="action" value="'.esc_attr(self::CHECK_ACTION).'">';
|
||||
wp_nonce_field(self::CHECK_ACTION);
|
||||
submit_button(esc_html__('Check for updates'), 'secondary', 'submit', false);
|
||||
echo '</form>';
|
||||
}
|
||||
|
||||
private function availableUpdate(?array $release = null): ?object
|
||||
{
|
||||
$release = $release ?? $this->latestRelease();
|
||||
|
||||
if (is_wp_error($release)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$version = $this->releaseVersion($release);
|
||||
$package = $this->releasePackage($release);
|
||||
|
||||
if ($version === '' || $package === null || !version_compare($version, MAHAK_AUTHENTICATE_BRIDGE_VERSION, '>')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'id' => $release['html_url'] ?? self::API_URL,
|
||||
'slug' => $this->slug,
|
||||
'plugin' => $this->plugin,
|
||||
'new_version' => $version,
|
||||
'url' => $release['html_url'] ?? '',
|
||||
'package' => $package,
|
||||
'requires_php' => '7.4',
|
||||
];
|
||||
}
|
||||
|
||||
private function latestRelease()
|
||||
{
|
||||
$cached = get_site_transient(self::RELEASE_CACHE);
|
||||
|
||||
if (is_array($cached)) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$response = wp_remote_get(self::API_URL, [
|
||||
'headers' => [
|
||||
'Accept' => 'application/vnd.github+json',
|
||||
'User-Agent' => 'Mahak-Authenticate-Bridge/'.MAHAK_AUTHENTICATE_BRIDGE_VERSION,
|
||||
],
|
||||
'timeout' => 10,
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return new \WP_Error('mahak_update_request_failed', 'Could not contact GitHub to check for plugin updates.');
|
||||
}
|
||||
|
||||
if (wp_remote_retrieve_response_code($response) !== 200) {
|
||||
return new \WP_Error('mahak_update_response_invalid', 'No published plugin release is currently available on GitHub.');
|
||||
}
|
||||
|
||||
$release = json_decode(wp_remote_retrieve_body($response), true);
|
||||
|
||||
if (!is_array($release) || !empty($release['draft']) || !empty($release['prerelease'])) {
|
||||
return new \WP_Error('mahak_update_release_invalid', 'GitHub returned invalid plugin release information.');
|
||||
}
|
||||
|
||||
if ($this->releaseVersion($release) === '' || $this->releasePackage($release) === null) {
|
||||
return new \WP_Error(
|
||||
'mahak_update_asset_missing',
|
||||
'The latest GitHub release does not contain a valid mahak-authenticate-bridge.zip package.'
|
||||
);
|
||||
}
|
||||
|
||||
set_site_transient(self::RELEASE_CACHE, $release, 6 * HOUR_IN_SECONDS);
|
||||
|
||||
return $release;
|
||||
}
|
||||
|
||||
private function releaseVersion(array $release): string
|
||||
{
|
||||
return ltrim((string) ($release['tag_name'] ?? ''), 'vV');
|
||||
}
|
||||
|
||||
private function releasePackage(array $release): ?string
|
||||
{
|
||||
foreach (($release['assets'] ?? []) as $asset) {
|
||||
if (($asset['name'] ?? '') !== self::RELEASE_ASSET) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = esc_url_raw((string) ($asset['browser_download_url'] ?? ''));
|
||||
|
||||
$path = (string) wp_parse_url($url, PHP_URL_PATH);
|
||||
|
||||
if (
|
||||
$url !== ''
|
||||
&& wp_parse_url($url, PHP_URL_SCHEME) === 'https'
|
||||
&& wp_parse_url($url, PHP_URL_HOST) === 'github.com'
|
||||
&& strpos($path, '/dabestaniha/mahak-authenticate-bridge/releases/download/') === 0
|
||||
) {
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user