✨feature: Add github repo update functions
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
/**
|
||||
* GitHub-based plugin updater.
|
||||
*
|
||||
* Hooks into WordPress's native update system so the plugin receives update
|
||||
* notifications sourced from GitHub releases rather than the wp.org directory.
|
||||
*
|
||||
* @package LogoSoup\Support
|
||||
*/
|
||||
|
||||
namespace LogoSoup\Support;
|
||||
|
||||
/**
|
||||
* Enables automatic plugin updates sourced from GitHub releases.
|
||||
*/
|
||||
class GitHub_Updater {
|
||||
|
||||
const GITHUB_USER = 'Vincent-Design-Inc';
|
||||
const GITHUB_REPO = 'Logo-Soup';
|
||||
const TRANSIENT = 'logo_soup_github_release';
|
||||
const TRANSIENT_TTL = 43200; // 12 hours.
|
||||
|
||||
/**
|
||||
* Plugin slug (relative path from plugins dir, e.g. logo-soup/logo-soup.php).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $plugin_slug;
|
||||
|
||||
/**
|
||||
* Absolute path to the main plugin file.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $plugin_file;
|
||||
|
||||
/**
|
||||
* Currently installed version, read from plugin headers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $current_version;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $plugin_file Absolute path to the main plugin file.
|
||||
*/
|
||||
public function __construct( $plugin_file ) {
|
||||
$this->plugin_file = $plugin_file;
|
||||
$this->plugin_slug = plugin_basename( $plugin_file );
|
||||
|
||||
$headers = get_file_data( $plugin_file, array( 'Version' => 'Version' ) );
|
||||
$this->current_version = ! empty( $headers['Version'] ) ? $headers['Version'] : '0.0.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register WordPress hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'inject_update' ) );
|
||||
add_filter( 'plugins_api', array( $this, 'plugin_info' ), 20, 3 );
|
||||
add_filter( 'upgrader_process_complete', array( $this, 'purge_transient' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject update data into WordPress's update_plugins transient.
|
||||
*
|
||||
* @param object $transient The update_plugins transient value.
|
||||
* @return object
|
||||
*/
|
||||
public function inject_update( $transient ) {
|
||||
if ( empty( $transient->checked ) ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$release = $this->fetch_latest_release();
|
||||
|
||||
if ( ! $release ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$remote_version = ltrim( $release['tag_name'], 'v' );
|
||||
|
||||
if ( version_compare( $this->current_version, $remote_version, '>=' ) ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$download_url = $this->get_download_url( $release );
|
||||
|
||||
if ( ! $download_url ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$transient->response[ $this->plugin_slug ] = (object) array(
|
||||
'slug' => dirname( $this->plugin_slug ),
|
||||
'plugin' => $this->plugin_slug,
|
||||
'new_version' => $remote_version,
|
||||
'url' => 'https://github.com/' . self::GITHUB_USER . '/' . self::GITHUB_REPO,
|
||||
'package' => $download_url,
|
||||
);
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply plugin info for the "View version details" modal in the admin.
|
||||
*
|
||||
* @param false|object|array $result The result object or array, or false.
|
||||
* @param string $action The type of info being requested.
|
||||
* @param object $args Plugin API arguments.
|
||||
* @return false|object
|
||||
*/
|
||||
public function plugin_info( $result, $action, $args ) {
|
||||
if ( 'plugin_information' !== $action ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( ! isset( $args->slug ) || dirname( $this->plugin_slug ) !== $args->slug ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$release = $this->fetch_latest_release();
|
||||
|
||||
if ( ! $release ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$remote_version = ltrim( $release['tag_name'], 'v' );
|
||||
$download_url = $this->get_download_url( $release );
|
||||
$changelog = ! empty( $release['body'] ) ? nl2br( esc_html( $release['body'] ) ) : '';
|
||||
|
||||
return (object) array(
|
||||
'name' => 'Logo Soup',
|
||||
'slug' => dirname( $this->plugin_slug ),
|
||||
'version' => $remote_version,
|
||||
'author' => 'Vincent Design Inc',
|
||||
'homepage' => 'https://github.com/' . self::GITHUB_USER . '/' . self::GITHUB_REPO,
|
||||
'download_link' => $download_url,
|
||||
'trunk' => $download_url,
|
||||
'requires' => '6.1',
|
||||
'requires_php' => '7.4',
|
||||
'sections' => array(
|
||||
'description' => esc_html__( 'Build balanced logo grids and marquees directly inside the WordPress block editor.', 'logo-soup' ),
|
||||
'changelog' => $changelog,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the cached release transient after a successful plugin update.
|
||||
*
|
||||
* @param \WP_Upgrader $upgrader Upgrader instance.
|
||||
* @param array $hook_extra Extra data about the upgrade.
|
||||
* @return void
|
||||
*/
|
||||
public function purge_transient( $upgrader, $hook_extra ) {
|
||||
if (
|
||||
! empty( $hook_extra['action'] ) &&
|
||||
'update' === $hook_extra['action'] &&
|
||||
! empty( $hook_extra['type'] ) &&
|
||||
'plugin' === $hook_extra['type'] &&
|
||||
! empty( $hook_extra['plugins'] ) &&
|
||||
in_array( $this->plugin_slug, (array) $hook_extra['plugins'], true )
|
||||
) {
|
||||
delete_transient( self::TRANSIENT );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the latest GitHub release, with a 12-hour transient cache.
|
||||
*
|
||||
* @return array|null Decoded release data or null on failure.
|
||||
*/
|
||||
private function fetch_latest_release() {
|
||||
$cached = get_transient( self::TRANSIENT );
|
||||
|
||||
if ( is_array( $cached ) ) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$url = sprintf(
|
||||
'https://api.github.com/repos/%s/%s/releases/latest',
|
||||
self::GITHUB_USER,
|
||||
self::GITHUB_REPO
|
||||
);
|
||||
|
||||
$response = wp_remote_get(
|
||||
$url,
|
||||
array(
|
||||
'timeout' => 10,
|
||||
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . get_bloginfo( 'url' ),
|
||||
'headers' => array(
|
||||
'Accept' => 'application/vnd.github+json',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
|
||||
if ( ! is_array( $data ) || empty( $data['tag_name'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
set_transient( self::TRANSIENT, $data, self::TRANSIENT_TTL );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the zip download URL from a release.
|
||||
*
|
||||
* Prefers an attached release asset (.zip); falls back to the auto-generated
|
||||
* GitHub source zipball.
|
||||
*
|
||||
* @param array $release Decoded GitHub release data.
|
||||
* @return string|null
|
||||
*/
|
||||
private function get_download_url( array $release ) {
|
||||
if ( ! empty( $release['assets'] ) && is_array( $release['assets'] ) ) {
|
||||
foreach ( $release['assets'] as $asset ) {
|
||||
if (
|
||||
isset( $asset['browser_download_url'] ) &&
|
||||
'.zip' === substr( $asset['browser_download_url'], -4 )
|
||||
) {
|
||||
return $asset['browser_download_url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isset( $release['zipball_url'] ) ? $release['zipball_url'] : null;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ namespace LogoSoup;
|
||||
use LogoSoup\Admin\Settings_Page;
|
||||
use LogoSoup\Blocks\Logo_Soup_Block;
|
||||
use LogoSoup\REST\Settings_Controller;
|
||||
use LogoSoup\Support\GitHub_Updater;
|
||||
|
||||
/**
|
||||
* Main plugin bootstrap class.
|
||||
@@ -34,6 +35,8 @@ class Plugin {
|
||||
register_activation_hook( $plugin_file, array( Installer::class, 'activate' ) );
|
||||
register_deactivation_hook( $plugin_file, array( Installer::class, 'deactivate' ) );
|
||||
|
||||
( new GitHub_Updater( $plugin_file ) )->register();
|
||||
|
||||
add_action( 'plugins_loaded', array( __CLASS__, 'load_textdomain' ) );
|
||||
add_action( 'init', array( __CLASS__, 'register_settings' ) );
|
||||
add_action( 'init', array( Logo_Soup_Block::class, 'register' ) );
|
||||
|
||||
Reference in New Issue
Block a user