array( 'success', __( 'Server created.', 'acrossai-mcp-manager' ) ),
'server_saved' => array( 'success', __( 'Server saved.', 'acrossai-mcp-manager' ) ),
'server_deleted' => array( 'success', __( 'Server deleted.', 'acrossai-mcp-manager' ) ),
'server_toggled' => array( 'success', __( 'Server status toggled.', 'acrossai-mcp-manager' ) ),
'bulk_completed' => array( 'success', __( 'Bulk action completed.', 'acrossai-mcp-manager' ) ),
'slug_exists' => array( 'error', __( 'Slug already in use.', 'acrossai-mcp-manager' ) ),
'empty_name' => array( 'error', __( 'Server name is required.', 'acrossai-mcp-manager' ) ),
'db_error' => array( 'error', __( 'Database write failed.', 'acrossai-mcp-manager' ) ),
'server_not_found' => array( 'error', __( 'Server not found.', 'acrossai-mcp-manager' ) ),
);
if ( ! isset( $messages[ $notice ] ) ) {
return;
}
printf(
'
',
esc_attr( $messages[ $notice ][0] ),
esc_html( $messages[ $notice ][1] )
);
}
// ─────────────────────────────────────────────────────────────────────────
// FR-015 / Q3 — Adapter-missing notice (render + dismissal).
// Contract: specs/002-admin-ui/contracts/notice-dismissal.md
// ─────────────────────────────────────────────────────────────────────────
/**
* Render a dismissible warning when the WordPress MCP adapter package is
* missing. Short-circuits on (a) adapter present, (b) sticky per-user dismissal.
* Wired on `admin_notices`.
*/
public function render_missing_adapter_notice(): void {
if ( class_exists( '\WP\MCP\Plugin' ) ) {
return; // Adapter installed — nothing to surface.
}
if ( get_user_meta( get_current_user_id(), self::ADAPTER_DISMISS_META_KEY, true ) ) {
return; // User already dismissed it — Q3 sticky semantics.
}
$nonce = wp_create_nonce( self::ADAPTER_DISMISS_NONCE_ACTION );
printf(
'',
esc_attr( $nonce ),
esc_html__( 'The WordPress MCP adapter package is not installed. MCP servers will not respond until you install the wordpress/mcp-adapter package.', 'acrossai-mcp-manager' )
);
}
/**
* Admin-ajax handler: persist the user's dismissal of the adapter notice.
* Wired on `wp_ajax_acrossai_mcp_dismiss_adapter_notice`.
*
* Idempotent: setting the meta to 1 when already 1 is a no-op success.
*/
public function handle_adapter_notice_dismissal(): void {
check_ajax_referer( self::ADAPTER_DISMISS_NONCE_ACTION );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => 'forbidden' ), 403 );
}
update_user_meta(
get_current_user_id(),
self::ADAPTER_DISMISS_META_KEY,
1
);
wp_send_json_success();
}
/**
* Render a warning when the site is not running HTTPS, per spec
* §Assumptions ("warning-not-block") and Edge Case for
* `client_secret` interception. Wired on `admin_notices`.
*
* Soft-warn only — the token endpoint still issues tokens on plain
* HTTP so local-dev keeps working. Production deployments MUST
* configure HTTPS.
*/
public function render_oauth_https_notice(): void {
if ( is_ssl() || ( defined( 'FORCE_SSL_ADMIN' ) && \FORCE_SSL_ADMIN ) ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
printf(
'',
esc_html__( 'AcrossAI MCP Manager:', 'acrossai-mcp-manager' ),
esc_html__( 'HTTPS is not configured. OAuth tokens will be issued over plaintext HTTP — passive network attackers can intercept them. Configure SSL / FORCE_SSL_ADMIN before exposing the OAuth endpoints to production traffic.', 'acrossai-mcp-manager' )
);
}
/**
* Render a warning when DISABLE_WP_CRON=true so operators know the
* daily OAuth cleanup will NOT run automatically. Suggests the
* WP-CLI fallback `wp acrossai-mcp oauth cleanup`. Wired on
* `admin_notices` (Phase 5 FR-019b follow-up).
*/
public function render_disable_wp_cron_notice(): void {
if ( ! ( defined( 'DISABLE_WP_CRON' ) && true === \DISABLE_WP_CRON ) ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
printf(
'',
esc_html__( 'AcrossAI MCP Manager:', 'acrossai-mcp-manager' ),
esc_html__( 'WP-Cron is disabled (DISABLE_WP_CRON=true). The daily OAuth cleanup will not run automatically. Schedule the WP-CLI command instead: wp acrossai-mcp oauth cleanup.', 'acrossai-mcp-manager' )
);
}
}