Skip to content

Commit e3dae04

Browse files
committed
refactor: replace inline styles with shared admin.css stylesheet
Add a shared admin CSS file loaded on all WorkOS admin screens via webpack. Move inline styles from Settings, Diagnostics, Onboarding, and Changelog pages into CSS classes. Add ChangelogPage for in-admin changelog viewing.
1 parent eef6536 commit e3dae04

19 files changed

Lines changed: 562 additions & 58 deletions

‎AGENTS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
Enterprise identity management for WordPress powered by WorkOS. SSO, directory sync, MFA, and user management.
66

7-
- **Version:** 1.0.0-dev
7+
- **Version:** 1.0.0
88
- **Namespace:** `WorkOS\`
99
- **PHP Requirement:** 7.4+
1010
- **WordPress Requirement:** 5.9+

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Changelog
22

3-
## [1.0.0-dev] - Unreleased
3+
## [1.0.0] - Unreleased
44

55
### Added
66
- AuthKit redirect and headless API authentication flows.

‎README.md‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,28 @@ Enterprise identity management for WordPress powered by [WorkOS](https://workos.
2424
- **Password Reset Integration** — redirect password reset to WorkOS or fall back to WordPress
2525
- **Registration Redirect** — redirect registration to WorkOS AuthKit
2626
- **Admin Bar Badge** — shows the active WorkOS environment (production/staging) in the admin bar
27+
- **Changelog Page** — in-admin changelog viewer rendered from CHANGELOG.md
2728
- **Diagnostics Page** — system health checks and configuration status
2829
- **Onboarding Wizard** — guided setup for initial plugin configuration and user sync
2930
- **WP-CLI Commands** — full CLI access for scripting, bulk operations, and diagnostics
3031

3132
## Installation
3233

33-
1. Upload the plugin to `wp-content/plugins/integration-workos/`.
34-
2. Run `composer install` in the plugin directory.
35-
3. Activate the plugin in WordPress admin.
34+
### From a Release ZIP
35+
36+
1. Download the latest `.zip` from the [Releases](https://github.com/bordoni/integration-workos/releases) page.
37+
2. In WordPress admin, go to **Plugins > Add New > Upload Plugin** and upload the ZIP file.
38+
3. Activate the plugin.
3639
4. Navigate to **Settings > WorkOS** to configure.
3740

41+
### From Source (Development)
42+
43+
1. Clone the repository into `wp-content/plugins/integration-workos/`.
44+
2. Run `composer install` to install PHP dependencies.
45+
3. Run `bun install && bun run build` to install JS dependencies and build assets.
46+
4. Activate the plugin in WordPress admin.
47+
5. Navigate to **Settings > WorkOS** to configure.
48+
3849
## Configuration
3950

4051
### Admin UI

‎bun.lock‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎integration-workos.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: Integration with WorkOS
44
* Plugin URI: https://github.com/bordoni/integration-workos
55
* Description: Enterprise identity management for WordPress powered by WorkOS. SSO, directory sync, MFA, and user management.
6-
* Version: 1.0.0-dev
6+
* Version: 1.0.0
77
* Author: Gustavo Bordoni
88
* Author URI: https://github.com/bordoni
99
* License: GPL-2.0-or-later

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "@liquidweb/workos-identity",
3-
"version": "1.0.0-dev",
2+
"name": "integration-workos",
3+
"version": "1.0.0",
44
"description": "Enterprise identity management for WordPress powered by WorkOS.",
55
"private": true,
66
"scripts": {

‎readme.txt‎

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Tags: sso, identity, workos, authentication, directory-sync
44
Requires at least: 5.9
55
Tested up to: 6.7
66
Requires PHP: 7.4
7-
Stable tag: 1.0.0-dev
7+
Stable tag: 1.0.0
88
License: GPL-2.0-or-later
99
License URI: https://www.gnu.org/licenses/gpl-2.0.html
1010

@@ -29,16 +29,28 @@ Integration with WorkOS connects your WordPress site with [WorkOS](https://worko
2929
* **Registration Redirect** — Redirect registration to WorkOS AuthKit.
3030
* **REST API Authentication** — Verify WorkOS access tokens for headless/API usage.
3131
* **Admin Bar Badge** — Shows the active WorkOS environment (production/staging) in the admin bar.
32+
* **Changelog Page** — In-admin changelog viewer rendered from CHANGELOG.md.
3233
* **Diagnostics Page** — System health checks, configuration status, and connectivity tests.
3334
* **Onboarding Wizard** — Guided setup for initial plugin configuration and user sync.
3435
* **WP-CLI Commands** — Full CLI access for scripting, bulk operations, and diagnostics.
3536

3637
== Installation ==
3738

38-
1. Upload the `integration-workos` folder to `/wp-content/plugins/`.
39-
2. Activate the plugin through the **Plugins** menu in WordPress.
40-
3. Go to **WorkOS > Settings** and enter your API Key and Client ID from the [WorkOS Dashboard](https://dashboard.workos.com).
41-
4. Configure your webhook endpoint in the WorkOS Dashboard using the URL shown on the settings page.
39+
= From a Release ZIP =
40+
41+
1. Download the latest `.zip` from the [Releases page](https://github.com/bordoni/integration-workos/releases).
42+
2. In WordPress admin, go to **Plugins > Add New > Upload Plugin** and upload the ZIP file.
43+
3. Activate the plugin.
44+
4. Go to **Settings > WorkOS** and enter your API Key and Client ID from the [WorkOS Dashboard](https://dashboard.workos.com).
45+
5. Configure your webhook endpoint in the WorkOS Dashboard using the URL shown on the settings page.
46+
47+
= From Source (Development) =
48+
49+
1. Clone the repository into `/wp-content/plugins/integration-workos/`.
50+
2. Run `composer install` to install PHP dependencies.
51+
3. Run `bun install && bun run build` to install JS dependencies and build assets.
52+
4. Activate the plugin through the **Plugins** menu in WordPress.
53+
5. Go to **Settings > WorkOS** to configure.
4254

4355
== Frequently Asked Questions ==
4456

@@ -265,7 +277,7 @@ Parameters:
265277

266278
== Changelog ==
267279

268-
= 1.0.0-dev =
280+
= 1.0.0 =
269281
* SSO login via WorkOS AuthKit (redirect and headless modes).
270282
* Directory Sync (SCIM) for automatic user provisioning and deprovisioning.
271283
* Role mapping between WorkOS organization roles and WordPress roles.

‎src/WorkOS/Admin/ChangelogPage.php‎

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
<?php
2+
/**
3+
* Changelog admin page.
4+
*
5+
* @package WorkOS\Admin
6+
*/
7+
8+
namespace WorkOS\Admin;
9+
10+
defined( 'ABSPATH' ) || exit;
11+
12+
/**
13+
* Hidden admin page that renders the plugin changelog.
14+
*/
15+
class ChangelogPage {
16+
17+
/**
18+
* Constructor.
19+
*/
20+
public function __construct() {
21+
add_action( 'admin_menu', [ $this, 'register_menu' ] );
22+
}
23+
24+
/**
25+
* Register the hidden submenu page.
26+
*/
27+
public function register_menu(): void {
28+
add_submenu_page(
29+
'workos',
30+
__( 'Changelog', 'integration-workos' ),
31+
__( 'Changelog', 'integration-workos' ),
32+
'manage_options',
33+
'workos-changelog',
34+
[ $this, 'render_page' ]
35+
);
36+
37+
// Hidden from the sidebar via admin.css; the page remains accessible by URL.
38+
}
39+
40+
/**
41+
* Render the changelog page.
42+
*/
43+
public function render_page(): void {
44+
if ( ! current_user_can( 'manage_options' ) ) {
45+
return;
46+
}
47+
48+
$changelog_file = workos()->getDir() . 'CHANGELOG.md';
49+
if ( ! file_exists( $changelog_file ) ) {
50+
echo '<div class="wrap"><h1>' . esc_html__( 'Changelog', 'integration-workos' ) . '</h1>';
51+
echo '<p>' . esc_html__( 'Changelog file not found.', 'integration-workos' ) . '</p></div>';
52+
return;
53+
}
54+
55+
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
56+
$content = file_get_contents( $changelog_file );
57+
if ( false === $content ) {
58+
echo '<div class="wrap"><h1>' . esc_html__( 'Changelog', 'integration-workos' ) . '</h1>';
59+
echo '<p>' . esc_html__( 'Unable to read changelog.', 'integration-workos' ) . '</p></div>';
60+
return;
61+
}
62+
63+
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
64+
$filter_version = isset( $_GET['version'] ) ? sanitize_text_field( wp_unslash( $_GET['version'] ) ) : '';
65+
66+
$versions = $this->parse_changelog( $content );
67+
68+
if ( $filter_version ) {
69+
$versions = array_filter(
70+
$versions,
71+
static function ( array $entry ) use ( $filter_version ): bool {
72+
return $entry['version'] === $filter_version;
73+
}
74+
);
75+
}
76+
77+
?>
78+
<div class="wrap">
79+
<h1><?php esc_html_e( 'Changelog', 'integration-workos' ); ?></h1>
80+
81+
<?php if ( $filter_version && empty( $versions ) ) : ?>
82+
<p>
83+
<?php
84+
printf(
85+
/* translators: %s: version number */
86+
esc_html__( 'No changelog entry found for version %s.', 'integration-workos' ),
87+
esc_html( $filter_version )
88+
);
89+
?>
90+
<a href="<?php echo esc_url( admin_url( 'admin.php?page=workos-changelog' ) ); ?>">
91+
<?php esc_html_e( 'View full changelog', 'integration-workos' ); ?>
92+
</a>
93+
</p>
94+
<?php endif; ?>
95+
96+
<?php foreach ( $versions as $entry ) : ?>
97+
<div class="workos-changelog-entry">
98+
<h2>
99+
<?php
100+
echo esc_html( $entry['version'] );
101+
if ( $entry['date'] ) {
102+
echo ' <small>— ' . esc_html( $entry['date'] ) . '</small>';
103+
}
104+
?>
105+
</h2>
106+
<?php echo wp_kses_post( $entry['html'] ); ?>
107+
</div>
108+
<?php endforeach; ?>
109+
110+
<?php if ( $filter_version && ! empty( $versions ) ) : ?>
111+
<p>
112+
<a href="<?php echo esc_url( admin_url( 'admin.php?page=workos-changelog' ) ); ?>">
113+
<?php esc_html_e( 'View full changelog', 'integration-workos' ); ?>
114+
</a>
115+
</p>
116+
<?php endif; ?>
117+
</div>
118+
<?php
119+
}
120+
121+
/**
122+
* Parse a Keep a Changelog-style markdown file into version entries.
123+
*
124+
* @param string $content Raw markdown content.
125+
*
126+
* @return array[] Array of [ 'version' => string, 'date' => string, 'html' => string ].
127+
*/
128+
private function parse_changelog( string $content ): array {
129+
// Split by version headings: ## [version] or ## [version] - date.
130+
$parts = preg_split( '/^## \[/m', $content );
131+
if ( ! $parts ) {
132+
return [];
133+
}
134+
135+
// First part is the file header (# Changelog), skip it.
136+
array_shift( $parts );
137+
138+
$entries = [];
139+
140+
foreach ( $parts as $part ) {
141+
// Extract version and optional date from the first line.
142+
if ( ! preg_match( '/^([^\]]+)\]\s*(?:-\s*(.+))?/m', $part, $matches ) ) {
143+
continue;
144+
}
145+
146+
$version = trim( $matches[1] );
147+
$date = isset( $matches[2] ) ? trim( $matches[2] ) : '';
148+
149+
// Remove the first line (version heading) from content.
150+
$body = preg_replace( '/^[^\n]*\n/', '', $part );
151+
$html = $this->markdown_to_html( $body );
152+
153+
$entries[] = [
154+
'version' => $version,
155+
'date' => $date,
156+
'html' => $html,
157+
];
158+
}
159+
160+
return $entries;
161+
}
162+
163+
/**
164+
* Convert simple changelog markdown to HTML.
165+
*
166+
* Supports ### headings and - list items.
167+
*
168+
* @param string $markdown Raw markdown body.
169+
*
170+
* @return string HTML output.
171+
*/
172+
private function markdown_to_html( string $markdown ): string {
173+
$lines = explode( "\n", trim( $markdown ) );
174+
$html = '';
175+
$in_list = false;
176+
177+
foreach ( $lines as $line ) {
178+
$trimmed = trim( $line );
179+
180+
if ( '' === $trimmed ) {
181+
if ( $in_list ) {
182+
$html .= "</ul>\n";
183+
$in_list = false;
184+
}
185+
continue;
186+
}
187+
188+
// ### Section headings.
189+
if ( str_starts_with( $trimmed, '### ' ) ) {
190+
if ( $in_list ) {
191+
$html .= "</ul>\n";
192+
$in_list = false;
193+
}
194+
$heading = substr( $trimmed, 4 );
195+
$html .= '<h3>' . esc_html( $heading ) . "</h3>\n";
196+
continue;
197+
}
198+
199+
// - List items.
200+
if ( str_starts_with( $trimmed, '- ' ) ) {
201+
if ( ! $in_list ) {
202+
$html .= "<ul>\n";
203+
$in_list = true;
204+
}
205+
$item = substr( $trimmed, 2 );
206+
$html .= '<li>' . esc_html( $item ) . "</li>\n";
207+
continue;
208+
}
209+
210+
// Plain text fallback.
211+
if ( $in_list ) {
212+
$html .= "</ul>\n";
213+
$in_list = false;
214+
}
215+
$html .= '<p>' . esc_html( $trimmed ) . "</p>\n";
216+
}
217+
218+
if ( $in_list ) {
219+
$html .= "</ul>\n";
220+
}
221+
222+
return $html;
223+
}
224+
}

‎src/WorkOS/Admin/Controller.php‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ protected function doRegister(): void {
4646

4747
$this->container->singleton( OnboardingAjax::class );
4848
$this->container->get( OnboardingAjax::class );
49+
50+
$this->container->singleton( ChangelogPage::class );
51+
$this->container->get( ChangelogPage::class );
4952
}
5053

5154
/**

0 commit comments

Comments
 (0)