connection = $connection; $this->stand = $stand; } /** * Hooks, when the Abilities API exists. */ public function register(): void { if ( ! function_exists( 'wp_register_ability' ) || ! function_exists( 'wp_register_ability_category' ) ) { return; } add_action( 'wp_abilities_api_categories_init', array( $this, 'category' ) ); add_action( 'wp_abilities_api_init', array( $this, 'abilities' ) ); } /** * Registers the category. */ public function category(): void { wp_register_ability_category( 'stand-chat', array( 'label' => __( 'Stand Chat', 'stand-chat' ), 'description' => __( 'Chat on this site and the AI assistant that answers it.', 'stand-chat' ), ) ); } /** * Registers the abilities. */ public function abilities(): void { $permission = static function (): bool { return current_user_can( Admin::capability() ); }; wp_register_ability( 'stand-chat/get-status', array( 'label' => __( 'Get chat status', 'stand-chat' ), 'description' => __( 'Whether chat is live on this site, and if not, why: off, hidden on this environment, waiting for installation, no one answering, or chats used up.', 'stand-chat' ), 'category' => 'stand-chat', 'output_schema' => array( 'type' => 'object', 'properties' => array( 'state' => array( 'type' => 'string' ), 'title' => array( 'type' => 'string' ), 'message' => array( 'type' => 'string' ), ), ), 'execute_callback' => function () { $status = Status::compute( $this->connection, $this->stand ); return array( 'state' => $status['state'], 'title' => $status['title'], 'message' => $status['message'], ); }, 'permission_callback' => $permission, 'meta' => array( 'annotations' => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true, ), ), ) ); wp_register_ability( 'stand-chat/read-page-again', array( 'label' => __( 'Read a page again', 'stand-chat' ), 'description' => __( 'Asks Stand to read a page the AI assistant reads again, after it was edited.', 'stand-chat' ), 'category' => 'stand-chat', 'input_schema' => array( 'type' => 'object', 'properties' => array( 'post_id' => array( 'type' => 'integer', 'minimum' => 1, ), ), 'required' => array( 'post_id' ), ), 'execute_callback' => function ( $input ) { $id = absint( is_array( $input ) ? ( $input['post_id'] ?? 0 ) : 0 ); if ( '' === (string) get_post_meta( $id, Knowledge::META_SOURCE, true ) ) { return new \WP_Error( 'stand_chat_not_picked', __( 'Your AI assistant doesn\'t read this page.', 'stand-chat' ) ); } // On the connection the request began on, as a page's changes // are: nobody connects or disconnects until it's asked. $errors = $this->stand->on_loaded_connection( null, function () use ( $id ): array { return ( new Knowledge( $this->stand ) )->read_again( array( $id ) ); } ); if ( is_wp_error( $errors ) ) { return $errors; } return empty( $errors ) ? array( 'requested' => true ) : new \WP_Error( 'stand_chat_read_again', (string) reset( $errors ) ); }, 'permission_callback' => $permission, 'meta' => array( 'annotations' => array( 'readonly' => false, 'destructive' => false, // Each call starts another reading in Stand. 'idempotent' => false, ), ), ) ); wp_register_ability( 'stand-chat/set-chat-enabled', array( 'label' => __( 'Turn chat on or off', 'stand-chat' ), 'description' => __( 'Turns "Chat on this site" on or off. Settings are kept.', 'stand-chat' ), 'category' => 'stand-chat', 'input_schema' => array( 'type' => 'object', 'properties' => array( 'enabled' => array( 'type' => 'boolean' ), ), 'required' => array( 'enabled' ), ), 'execute_callback' => static function ( $input ) { $enabled = is_array( $input ) && ! empty( $input['enabled'] ); Settings::update( array( 'chat_enabled' => $enabled ) ); return array( 'enabled' => $enabled ); }, 'permission_callback' => $permission, 'meta' => array( 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true, ), ), ) ); } }