diff --git a/src/Admin/AdminPostAction.php b/src/Admin/AdminPostAction.php index 6d3358e..ae4fe1b 100644 --- a/src/Admin/AdminPostAction.php +++ b/src/Admin/AdminPostAction.php @@ -32,10 +32,14 @@ final class AdminPostAction } } - /** Redirects to settings tab $slug with "lit_mcp_notice" = $notice and ends the request. */ - public function redirect(string $slug, string $notice): void + /** + * Redirects to settings tab $slug with "lit_mcp_notice" = $notice (and further query $args) and ends the request. + * + * @param array $args + */ + public function redirect(string $slug, string $notice, array $args = []): void { - wp_safe_redirect(SettingsPage::url($slug, ['lit_mcp_notice' => $notice])); + wp_safe_redirect(SettingsPage::url($slug, ['lit_mcp_notice' => $notice] + $args)); ($this->terminate)(); } } diff --git a/src/Admin/CheckRoute.php b/src/Admin/CheckRoute.php new file mode 100644 index 0000000..efc6e60 --- /dev/null +++ b/src/Admin/CheckRoute.php @@ -0,0 +1,184 @@ +-check, one route per + * profile. A REST request on purpose – not admin-post – so the check runs in the same context as MCP calls (Divi + * renders its blocks in REST requests, lit-page-render-summary). The form sends the wp_rest nonce as _wpnonce + * (cookie authentication); only manage_options. The profile comes from the route, which exists only for the + * profiles of Compatibility; handle() looks the ID up again, so an ID never reaches an option name unchecked. + * One check per profile at a time: an atomic "INSERT IGNORE" on the options table (lit_mcp__check_lock) is the + * lock – add_option() reads then writes (wp-includes/option.php) and is not atomic, so two simultaneous requests + * could both "acquire" it. The value is "