'mcp-adapter-plugin', 'tone' => 'warning', 'tone_label' => __( 'Needed soon', 'albert-ai-butler' ), 'title' => AdapterPlugin::title(), 'detail' => $can_fix ? AdapterPlugin::explanation() : AdapterPlugin::explanation() . ' ' . AdapterPlugin::guidance(), 'action' => $can_fix ? [ 'label' => AdapterPlugin::action_label(), 'url' => AdapterPlugin::fix_url(), 'attributes' => self::one_click_attributes(), ] : null, 'dismissible' => false, ]; return $items; } /** * The notice on every Albert screen except the Dashboard, which has its card. * * Administrators only: anyone else reaching Albert has only the Connect * page, and a warning they cannot act on reads as a fault in their setup. * * @return void * @since 1.5.0 */ public function render_screen_notice(): void { if ( ! Menu::is_albert_screen() || ! current_user_can( 'manage_options' ) ) { return; } $screen = get_current_screen(); if ( $screen !== null && $screen->id === 'toplevel_page_' . Menu::PARENT_SLUG ) { return; } wp_admin_notice( $this->message(), [ 'type' => 'warning', 'additional_classes' => [ 'albert-adapter-notice' ], 'paragraph_wrap' => false, ] ); } /** * Confirm the one-click install once the page reloads. * * Only when the plugin really is active, so the query argument alone proves * nothing. * * @return void * @since 1.5.0 */ public function render_done_notice(): void { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display only, and checked against the real state below. if ( ! isset( $_GET[ self::DONE_ARG ] ) || AdapterPlugin::needs_attention() || ! current_user_can( 'activate_plugins' ) ) { return; } wp_admin_notice( '' . esc_html__( 'The MCP Adapter plugin is installed and active.', 'albert-ai-butler' ) . ' ' . esc_html__( 'Albert now uses it to talk to your AI assistants.', 'albert-ai-butler' ), [ 'type' => 'success', 'dismissible' => true, 'additional_classes' => [ 'albert-adapter-notice' ], ] ); } /** * Let core strip the confirmation argument from the address bar. * * @param mixed $args Removable query arguments. * * @return mixed * @since 1.5.0 */ public function removable_query_args( $args ) { if ( is_array( $args ) ) { $args[] = self::DONE_ARG; } return $args; } /** * The notice under Albert on the Plugins screen, for owners who never open Albert. * * @return void * @since 1.5.0 */ public function render_plugin_row(): void { if ( ! current_user_can( 'activate_plugins' ) ) { return; } $list_table = $GLOBALS['wp_list_table'] ?? null; $columns = is_object( $list_table ) && method_exists( $list_table, 'get_column_count' ) ? (int) $list_table->get_column_count() : 3; $link = AdapterPlugin::current_user_can_fix() ? sprintf( ' %3$s.', esc_url( AdapterPlugin::fix_url() ), self::attribute_string(), esc_html( AdapterPlugin::action_label() ) ) : ' ' . esc_html( AdapterPlugin::guidance() ); // Core's own "new version available" row, so it reads as part of Albert's. printf( '
' . esc_html__( 'Albert talks to AI assistants through the MCP Adapter plugin.', 'albert-ai-butler' ) . '
', 'test' => 'albert_mcp_adapter_plugin', ]; if ( ! AdapterPlugin::needs_attention() ) { return $result; } $result['label'] = AdapterPlugin::title(); $result['status'] = 'recommended'; $result['badge']['color'] = 'orange'; $result['description'] = '' . esc_html( AdapterPlugin::explanation() ) . '
'; if ( AdapterPlugin::current_user_can_fix() ) { $result['actions'] = sprintf( '', esc_url( AdapterPlugin::fix_url() ), esc_html( AdapterPlugin::action_label() ) ); } else { $result['description'] .= '' . esc_html( AdapterPlugin::guidance() ) . '
'; } return $result; } /** * The button that installs or activates it, or what to do instead. * * Shared by the Dashboard's setup checklist, so it matches the notices. * * @return void * @since 1.5.0 */ public static function render_action(): void { if ( ! AdapterPlugin::current_user_can_fix() ) { printf( '%s
', esc_html( AdapterPlugin::guidance() ) ); return; } printf( '%3$s', esc_url( AdapterPlugin::fix_url() ), self::attribute_string(), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped in attribute_string(). esc_html( AdapterPlugin::action_label() ) ); } /** * The data attributes that turn the link into a one-click install. * * Empty where one click cannot do it, so the link goes to core's own screen. * * @return array%1$s %2$s
', esc_html( AdapterPlugin::title() . '.' ), esc_html( AdapterPlugin::explanation() ) ); if ( ! AdapterPlugin::current_user_can_fix() ) { return $html . '' . esc_html( AdapterPlugin::guidance() ) . '
'; } return $html . sprintf( '', esc_url( AdapterPlugin::fix_url() ), self::attribute_string(), esc_html( AdapterPlugin::action_label() ) ); } }