Skip to content

Commit f506dae

Browse files
committed
Add GitHub-based updater, bump to 0.9.1
Add a self-hosted update checker (includes/Updater.php) that queries GitHub Releases, caches results, and surfaces updates/details in the WP plugin interface. Instantiate and register the Updater in workos-for-wordpress.php and bump the plugin version to 0.9.1. Standardize produced artifact name to workos-for-wordpress.zip in bin/build-zip.sh and the release workflow, and update README with recommended release download and install-from-source instructions.
1 parent f5694c1 commit f506dae

5 files changed

Lines changed: 247 additions & 11 deletions

File tree

.github/workflows/release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
./ "$DEST/"
9090
9191
cd "$BUILD_DIR"
92-
zip -rq "$GITHUB_WORKSPACE/$PLUGIN_SLUG-$VERSION.zip" "$PLUGIN_SLUG"
92+
zip -rq "$GITHUB_WORKSPACE/$PLUGIN_SLUG.zip" "$PLUGIN_SLUG"
9393
9494
- name: Create tag and GitHub Release
9595
env:
@@ -99,6 +99,6 @@ jobs:
9999
git tag "v$VERSION"
100100
git push origin "v$VERSION"
101101
gh release create "v$VERSION" \
102-
"workos-for-wordpress-$VERSION.zip" \
102+
"workos-for-wordpress.zip" \
103103
--title "v$VERSION" \
104104
--generate-notes

README.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,32 @@ WordPress powers millions of business-critical sites, but its built-in authentic
3030

3131
## Installation
3232

33-
1. **Download or clone** the plugin into your WordPress plugins directory:
33+
### Download a Release (recommended)
34+
35+
1. **Download the latest zip** from [GitHub Releases](https://github.com/AlwaysCuriousCo/workos-for-wordpress/releases). The zip includes all dependencies — no Composer required.
36+
2. In your WordPress admin, go to **Plugins > Add New > Upload Plugin** and upload the zip.
37+
3. **Activate** the plugin.
38+
4. **Configure your credentials** under the new **WorkOS** menu in the admin sidebar.
39+
40+
### Install from Source
41+
42+
If you prefer to clone the repository directly:
43+
44+
1. Clone into your plugins directory:
3445

3546
```bash
3647
cd wp-content/plugins/
3748
git clone https://github.com/AlwaysCuriousCo/workos-for-wordpress.git
3849
```
3950

40-
2. **Install dependencies** via Composer:
51+
2. Install dependencies via Composer:
4152

4253
```bash
4354
cd workos-for-wordpress
4455
composer install
4556
```
4657

47-
3. **Activate the plugin** from the WordPress admin under Plugins.
48-
49-
4. **Configure your credentials** under the new **WorkOS** menu in the admin sidebar.
58+
3. **Activate** the plugin and configure under **WorkOS** in the admin sidebar.
5059

5160
---
5261

bin/build-zip.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# ./bin/build-zip.sh
77
#
88
# Output:
9-
# dist/workos-for-wordpress-{version}.zip
9+
# dist/workos-for-wordpress.zip
1010

1111
set -euo pipefail
1212

@@ -50,7 +50,7 @@ echo "Installed production dependencies."
5050

5151
# Create dist directory and zip.
5252
mkdir -p "$DIST_DIR"
53-
ZIP_FILE="$DIST_DIR/$PLUGIN_SLUG-$VERSION.zip"
53+
ZIP_FILE="$DIST_DIR/$PLUGIN_SLUG.zip"
5454
cd "$BUILD_DIR"
5555
zip -rq "$ZIP_FILE" "$PLUGIN_SLUG"
5656

includes/Updater.php

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
<?php
2+
3+
namespace AlwaysCurious\WorkOSWP;
4+
5+
defined('ABSPATH') || exit;
6+
7+
class Updater {
8+
9+
private string $plugin_file;
10+
private string $plugin_slug;
11+
private string $version;
12+
private string $github_repo = 'AlwaysCuriousCo/workos-for-wordpress';
13+
private string $cache_key = 'workos_wp_update_check';
14+
private int $cache_ttl = 43200; // 12 hours
15+
16+
public function __construct(string $plugin_file, string $version) {
17+
$this->plugin_file = $plugin_file;
18+
$this->plugin_slug = plugin_basename($plugin_file);
19+
$this->version = $version;
20+
}
21+
22+
public function register_hooks(): void {
23+
add_filter('pre_set_site_transient_update_plugins', [$this, 'check_for_update']);
24+
add_filter('plugins_api', [$this, 'plugin_info'], 10, 3);
25+
add_filter('plugin_row_meta', [$this, 'plugin_row_meta'], 10, 2);
26+
27+
// Clear cache when WordPress forces an update check.
28+
add_action('delete_site_transient_update_plugins', [$this, 'clear_cache']);
29+
}
30+
31+
/**
32+
* Check GitHub for a newer release and inject it into the update transient.
33+
*/
34+
public function check_for_update(object $transient): object {
35+
if (empty($transient->checked)) {
36+
return $transient;
37+
}
38+
39+
$release = $this->get_latest_release();
40+
if (!$release) {
41+
return $transient;
42+
}
43+
44+
$remote_version = ltrim($release['tag_name'], 'v');
45+
46+
if (version_compare($this->version, $remote_version, '<')) {
47+
$transient->response[$this->plugin_slug] = (object) [
48+
'slug' => dirname($this->plugin_slug),
49+
'plugin' => $this->plugin_slug,
50+
'new_version' => $remote_version,
51+
'url' => $release['html_url'],
52+
'package' => $release['zip_url'],
53+
'icons' => [],
54+
'banners' => [],
55+
'tested' => '',
56+
'requires_php' => '8.1',
57+
'requires' => '6.4',
58+
];
59+
} else {
60+
// Tell WordPress we checked and there's no update.
61+
$transient->no_update[$this->plugin_slug] = (object) [
62+
'slug' => dirname($this->plugin_slug),
63+
'plugin' => $this->plugin_slug,
64+
'new_version' => $this->version,
65+
'url' => "https://github.com/{$this->github_repo}",
66+
'package' => '',
67+
];
68+
}
69+
70+
return $transient;
71+
}
72+
73+
/**
74+
* Provide plugin details for the "View details" modal in the update screen.
75+
*/
76+
public function plugin_info($result, string $action, object $args) {
77+
if ($action !== 'plugin_information') {
78+
return $result;
79+
}
80+
81+
if (!isset($args->slug) || $args->slug !== dirname($this->plugin_slug)) {
82+
return $result;
83+
}
84+
85+
$release = $this->get_latest_release();
86+
if (!$release) {
87+
return $result;
88+
}
89+
90+
$remote_version = ltrim($release['tag_name'], 'v');
91+
92+
return (object) [
93+
'name' => 'WorkOS for WordPress',
94+
'slug' => dirname($this->plugin_slug),
95+
'version' => $remote_version,
96+
'author' => '<a href="https://alwayscurious.co">Always Curious</a>',
97+
'homepage' => "https://github.com/{$this->github_repo}",
98+
'requires' => '6.4',
99+
'requires_php' => '8.1',
100+
'downloaded' => 0,
101+
'last_updated' => $release['published_at'],
102+
'sections' => [
103+
'description' => 'Enterprise-grade authentication and user management for WordPress, powered by WorkOS.',
104+
'changelog' => $this->format_changelog($release['body']),
105+
'installation' => 'Upload the plugin zip via <strong>Plugins &gt; Add New &gt; Upload Plugin</strong>, then activate and configure under the <strong>WorkOS</strong> menu.',
106+
],
107+
'download_link' => $release['zip_url'],
108+
'banners' => [],
109+
];
110+
}
111+
112+
/**
113+
* Add a "Check for updates" link in the plugin row on the Plugins page.
114+
*/
115+
public function plugin_row_meta(array $meta, string $file): array {
116+
if ($file !== $this->plugin_slug) {
117+
return $meta;
118+
}
119+
120+
$meta[] = sprintf(
121+
'<a href="%s">%s</a>',
122+
wp_nonce_url(admin_url('update-core.php?force-check=1'), 'upgrade-core'),
123+
__('Check for updates', 'workos-for-wordpress')
124+
);
125+
126+
return $meta;
127+
}
128+
129+
/**
130+
* Fetch the latest release from GitHub, with caching.
131+
*/
132+
private function get_latest_release(): ?array {
133+
$cached = get_transient($this->cache_key);
134+
if ($cached !== false) {
135+
return $cached ?: null;
136+
}
137+
138+
$response = wp_remote_get(
139+
"https://api.github.com/repos/{$this->github_repo}/releases/latest",
140+
[
141+
'headers' => [
142+
'Accept' => 'application/vnd.github.v3+json',
143+
'User-Agent' => 'WorkOS-WordPress-Plugin/' . $this->version,
144+
],
145+
'timeout' => 10,
146+
]
147+
);
148+
149+
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
150+
// Cache the failure so we don't hammer the API.
151+
set_transient($this->cache_key, '', $this->cache_ttl);
152+
return null;
153+
}
154+
155+
$body = json_decode(wp_remote_retrieve_body($response), true);
156+
if (empty($body['tag_name'])) {
157+
set_transient($this->cache_key, '', $this->cache_ttl);
158+
return null;
159+
}
160+
161+
// Find the plugin zip asset in the release.
162+
$zip_url = $this->find_zip_asset($body['assets'] ?? []);
163+
164+
$data = [
165+
'tag_name' => $body['tag_name'],
166+
'html_url' => $body['html_url'],
167+
'body' => $body['body'] ?? '',
168+
'published_at' => $body['published_at'] ?? '',
169+
'zip_url' => $zip_url,
170+
];
171+
172+
set_transient($this->cache_key, $data, $this->cache_ttl);
173+
174+
return $data;
175+
}
176+
177+
/**
178+
* Find the plugin zip from release assets.
179+
* Falls back to the GitHub source zip if no matching asset is found.
180+
*/
181+
private function find_zip_asset(array $assets): string {
182+
foreach ($assets as $asset) {
183+
if (
184+
str_starts_with($asset['name'], 'workos-for-wordpress') &&
185+
str_ends_with($asset['name'], '.zip')
186+
) {
187+
return $asset['browser_download_url'];
188+
}
189+
}
190+
191+
// Fallback: GitHub's auto-generated source zipball.
192+
return "https://github.com/{$this->github_repo}/releases/latest/download/workos-for-wordpress.zip";
193+
}
194+
195+
/**
196+
* Convert GitHub markdown release notes to basic HTML for the changelog tab.
197+
*/
198+
private function format_changelog(string $markdown): string {
199+
if (empty($markdown)) {
200+
return '<p>See the <a href="https://github.com/' . esc_attr($this->github_repo) . '/releases">release notes on GitHub</a>.</p>';
201+
}
202+
203+
// Basic markdown to HTML: headings, bold, lists, links.
204+
$html = esc_html($markdown);
205+
$html = preg_replace('/^### (.+)$/m', '<h4>$1</h4>', $html);
206+
$html = preg_replace('/^## (.+)$/m', '<h3>$1</h3>', $html);
207+
$html = preg_replace('/\*\*(.+?)\*\*/', '<strong>$1</strong>', $html);
208+
$html = preg_replace('/^\* (.+)$/m', '<li>$1</li>', $html);
209+
$html = preg_replace('/^- (.+)$/m', '<li>$1</li>', $html);
210+
$html = preg_replace('/(<li>.*<\/li>\n?)+/', '<ul>$0</ul>', $html);
211+
$html = nl2br($html);
212+
213+
return $html;
214+
}
215+
216+
/**
217+
* Clear the cached release data.
218+
*/
219+
public function clear_cache(): void {
220+
delete_transient($this->cache_key);
221+
}
222+
}

workos-for-wordpress.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: WorkOS for WordPress
44
* Plugin URI: https://github.com/AlwaysCuriousCo/workos-for-wordpress
55
* Description: Integrate WorkOS authentication and user management into WordPress.
6-
* Version: 0.9.0
6+
* Version: 0.9.1
77
* Author: Always Curious
88
* Author URI: https://alwayscurious.co
99
* License: GPL-3.0-or-later
@@ -15,7 +15,7 @@
1515

1616
defined('ABSPATH') || exit;
1717

18-
define('WORKOS_WP_VERSION', '0.9.0');
18+
define('WORKOS_WP_VERSION', '0.9.1');
1919
define('WORKOS_WP_PLUGIN_FILE', __FILE__);
2020
define('WORKOS_WP_PLUGIN_DIR', plugin_dir_path(__FILE__));
2121
define('WORKOS_WP_PLUGIN_URL', plugin_dir_url(__FILE__));
@@ -33,5 +33,10 @@
3333
require_once $autoloader;
3434

3535
use AlwaysCurious\WorkOSWP\Plugin;
36+
use AlwaysCurious\WorkOSWP\Updater;
3637

3738
Plugin::instance();
39+
40+
// Self-hosted update checker via GitHub Releases.
41+
$updater = new Updater(WORKOS_WP_PLUGIN_FILE, WORKOS_WP_VERSION);
42+
$updater->register_hooks();

0 commit comments

Comments
 (0)