attachment = new AltTextLab_Attachment(); } /** * Registers the AltTextLab ability category. */ public function register_categories() { if ( ! function_exists( 'wp_register_ability_category' ) ) { return; } wp_register_ability_category( 'alttextlab', array( 'label' => __( 'AltTextLab', 'alttextlab' ), 'description' => __( 'Abilities for generating image alt text with AltTextLab.', 'alttextlab' ), ) ); } /** * Registers AltTextLab abilities. */ public function register_abilities() { if ( ! function_exists( 'wp_register_ability' ) ) { return; } wp_register_ability( 'alttextlab/generate-alt-text', array( 'label' => __( 'Generate Alt Text', 'alttextlab' ), 'description' => __( 'Generates alt text for a single WordPress media attachment. Use this when the user wants to add or fix alt text for one specific image.', 'alttextlab' ), 'category' => 'alttextlab', 'input_schema' => array( 'type' => 'object', 'properties' => array( 'attachment_id' => array( 'type' => 'integer', 'description' => __( 'The WordPress media attachment ID to generate alt text for.', 'alttextlab' ), ), 'keywords' => array( 'type' => 'array', 'description' => __( 'Optional SEO key phrase(s) to target in the generated alt text (e.g. main search term for this image).', 'alttextlab' ), 'items' => array( 'type' => 'string', ), ), ), 'required' => array( 'attachment_id' ), ), 'execute_callback' => array( $this, 'generate_alt_text' ), 'permission_callback' => array( $this, 'can_generate_alt_text' ), 'meta' => array( 'show_in_rest' => true, 'mcp' => array( 'public' => true, ), ), ) ); wp_register_ability( 'alttextlab/scan-missing-alt-text', array( 'label' => __( 'Scan Missing Alt Text', 'alttextlab' ), 'description' => __( 'Finds WordPress media images that have no alt text or empty alt text. Returns their attachment IDs, which can then be passed to bulk-generate-alt-text to fill them in.', 'alttextlab' ), 'category' => 'alttextlab', 'input_schema' => array( 'type' => 'object', 'properties' => array( 'limit' => array( 'type' => 'integer', 'description' => __( 'Maximum number of images to return. Defaults to 20.', 'alttextlab' ), ), ), ), 'execute_callback' => array( $this, 'scan_missing_alt' ), 'permission_callback' => array( $this, 'can_scan_missing_alt' ), 'meta' => array( 'show_in_rest' => true, 'mcp' => array( 'public' => true, ), ), ) ); wp_register_ability( 'alttextlab/bulk-generate-alt-text', array( 'label' => __( 'Bulk Generate Alt Text', 'alttextlab' ), 'description' => __( 'Generates alt text for multiple WordPress media attachments at once. Typically used after scan-missing-alt-text to fill in alt text for all images that are missing it.', 'alttextlab' ), 'category' => 'alttextlab', 'input_schema' => array( 'type' => 'object', 'properties' => array( 'attachment_ids' => array( 'type' => 'array', 'description' => __( 'List of WordPress media attachment IDs to generate alt text for.', 'alttextlab' ), 'items' => array( 'type' => 'integer', ), ) ), 'required' => array( 'attachment_ids' ), ), 'execute_callback' => array( $this, 'bulk_generate_alt_text' ), 'permission_callback' => array( $this, 'can_bulk_generate_alt_text' ), 'meta' => array( 'show_in_rest' => true, 'mcp' => array( 'public' => true, ), ), ) ); } public function can_generate_alt_text( $input ) { return current_user_can( 'upload_files' ); } public function can_scan_missing_alt( $input ) { return current_user_can( 'upload_files' ); } public function can_bulk_generate_alt_text( $input ) { return current_user_can( 'upload_files' ); } /** * Generates alt text for a single media attachment. */ public function generate_alt_text( $input ) { $attachment_id = isset( $input['attachment_id'] ) ? absint( $input['attachment_id'] ) : 0; if ( ! $attachment_id ) { return $this->ability_error_response( $attachment_id, 'alttextlab_invalid_attachment_id', __( 'Invalid attachment ID.', 'alttextlab' ) ); } $keywords = $this->sanitize_keywords( $input['keywords'] ?? array() ); $alt_text = $this->attachment->generate_alt( $attachment_id, null, array( 'keywords' => $keywords, ) ); if ( $alt_text === AltTextLab_Attachment::ERROR_NO_CREDITS ) { return $this->ability_error_response( $attachment_id, 'alttextlab_no_credits', __( 'No AltTextLab credits available.', 'alttextlab' ) ); } if ( $alt_text === AltTextLab_Attachment::ERROR_INVALID_API_KEY ) { return $this->ability_error_response( $attachment_id, 'alttextlab_invalid_api_key', __( 'The AltTextLab API key is invalid.', 'alttextlab' ) ); } if ( $alt_text === AltTextLab_Attachment::ERROR_MONTHLY_LIMIT ) { return $this->ability_error_response( $attachment_id, 'alttextlab_monthly_limit', __( 'Monthly credit limit reached for this API key. Update it anytime in your AltTextLab account settings.', 'alttextlab' ) ); } if ( ! is_string( $alt_text ) || $alt_text === '' ) { return $this->ability_error_response( $attachment_id, 'alttextlab_generation_failed', __( 'Alt text generation failed.', 'alttextlab' ) ); } return array( 'success' => true, 'attachment_id' => $attachment_id, 'alt_text' => $alt_text, ); } /** * Finds media images that have missing or empty alt text. */ public function scan_missing_alt( $input ) { $limit = isset( $input['limit'] ) ? absint( $input['limit'] ) : 20; $images = $this->attachment->get_images_without_alt_text( $limit ); return array( 'success' => true, 'total_missing' => $this->attachment->get_images_without_alt_text_count(), 'count' => count( $images ), 'images' => $images, ); } /** * Generates alt text for multiple media attachments. */ public function bulk_generate_alt_text( $input ) { $attachment_ids = ! empty( $input['attachment_ids'] ) && is_array( $input['attachment_ids'] ) ? array_map( 'absint', $input['attachment_ids'] ) : array(); if ( empty( $attachment_ids ) ) { return $this->bulk_error_response( 'alttextlab_empty_attachment_ids', __( 'No attachment IDs provided.', 'alttextlab' ) ); } $api_key = AltTextLab_Utility::get_api_key(); if ( empty( $api_key ) ) { return $this->bulk_error_response( 'alttextlab_missing_api_key', __( 'AltTextLab API key is missing.', 'alttextlab' ) ); } return $this->attachment->bulk_generate_alt_text_for_attachments( $attachment_ids, array( 'run_id' => uniqid( 'ability_', true ), ) ); } private function sanitize_keywords( $keywords ) { if ( empty( $keywords ) || ! is_array( $keywords ) ) { return array(); } return array_values( array_filter( array_map( 'sanitize_text_field', $keywords ) ) ); } private function ability_error_response( $attachment_id, $error_code, $message ) { return array( 'success' => false, 'attachment_id' => absint( $attachment_id ), 'error_code' => $error_code, 'message' => $message, ); } private function bulk_error_response( $error_code, $message ) { return array( 'success' => false, 'processed' => 0, 'success_count' => 0, 'error_count' => 1, 'error_code' => $error_code, 'message' => $message, 'results' => array(), ); } }