Skip to content

Commit 4f80489

Browse files
authored
Merge pull request #26 from bordoni/fix/users-settings-nested-form-save
[CONS-505] fix(admin): unnest Sync Roles form so Users settings save
2 parents e186c3d + adc2e54 commit 4f80489

2 files changed

Lines changed: 48 additions & 6 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@
1818
- 40 new WPUnit tests across 6 suites under `tests/wpunit/ChangeEmail*Test.php`.
1919
- See [`docs/change-email.md`](docs/change-email.md).
2020

21+
### Fixed
22+
23+
- **WorkOS → Users settings would not save** — the "Sync Roles to
24+
WorkOS" button rendered its own `<form>` inside the Settings API
25+
`<form action="options.php">`. Browsers don't allow nested forms:
26+
the inner `</form>` closed the outer settings form early, and since
27+
Role Mapping is the last section, the "Save Settings" submit button
28+
was left outside the form. Clicking Save did nothing and no changes
29+
(logout redirects, deprovision action, role map, etc.) persisted.
30+
The sync form is now deferred to `admin_footer` (body level, like
31+
the Create Organization modal) and its button is wired back via the
32+
HTML5 `form="workos-role-sync-form"` attribute, so the settings form
33+
stays intact and saves normally.
34+
2135
## [1.0.5] - 2026-05-18
2236

2337
### Added

‎src/WorkOS/Admin/Settings.php‎

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ class Settings {
4343
*/
4444
private bool $create_org_modal_queued = false;
4545

46+
/**
47+
* Whether the role-sync form has been queued for footer render.
48+
*
49+
* @var bool
50+
*/
51+
private bool $role_sync_form_queued = false;
52+
4653
/**
4754
* Constructor.
4855
*/
@@ -1430,6 +1437,24 @@ public function render_create_org_modal(): void {
14301437
<?php
14311438
}
14321439

1440+
/**
1441+
* Render the hidden "Sync Roles to WorkOS" form.
1442+
*
1443+
* Hooked to admin_footer so its <form> sits at body level rather than nested
1444+
* inside the settings form on the Users tab. The visible submit button stays
1445+
* in the role-map actions row and is wired to this form via the HTML5 `form`
1446+
* attribute.
1447+
*/
1448+
public function render_role_sync_form(): void {
1449+
?>
1450+
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" id="workos-role-sync-form" style="display:none">
1451+
<?php wp_nonce_field( 'workos_sync_roles_to_workos' ); ?>
1452+
<input type="hidden" name="action" value="workos_sync_roles_to_workos" />
1453+
<input type="hidden" name="editing_env" value="<?php echo esc_attr( $this->get_editing_environment() ); ?>" />
1454+
</form>
1455+
<?php
1456+
}
1457+
14331458
/**
14341459
* Flush the organizations transient cache.
14351460
*/
@@ -1650,16 +1675,19 @@ public function render_role_map(): void {
16501675
echo '</button>';
16511676

16521677
// Sync Roles to WorkOS button — only when plugin is enabled and org is configured.
1678+
// The actual <form> is deferred to admin_footer (see render_role_sync_form) so it is
1679+
// not nested inside the outer options.php settings form. A nested <form> closes the
1680+
// settings form early, orphaning the "Save Settings" button so nothing persists.
16531681
if ( workos()->is_enabled() && ! empty( Config::get_organization_id() ) ) {
1654-
echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" id="workos-role-sync-form">';
1655-
wp_nonce_field( 'workos_sync_roles_to_workos' );
1656-
echo '<input type="hidden" name="action" value="workos_sync_roles_to_workos" />';
1657-
echo '<input type="hidden" name="editing_env" value="' . esc_attr( $this->get_editing_environment() ) . '" />';
1658-
echo '<button type="submit" class="button">';
1682+
echo '<button type="submit" form="workos-role-sync-form" class="button">';
16591683
echo '<span class="dashicons dashicons-update"></span> ';
16601684
echo esc_html__( 'Sync Roles to WorkOS', 'integration-workos' );
16611685
echo '</button>';
1662-
echo '</form>';
1686+
1687+
if ( ! $this->role_sync_form_queued ) {
1688+
add_action( 'admin_footer', [ $this, 'render_role_sync_form' ] );
1689+
$this->role_sync_form_queued = true;
1690+
}
16631691
}
16641692

16651693
echo '</div>';

0 commit comments

Comments
 (0)