$aspect_ratio, ); if ( ! empty( $image_size ) ) { $image_config['imageSize'] = $image_size; } $body = array( 'contents' => array( array( 'parts' => array( array( 'text' => $prompt ), ), ), ), 'generationConfig' => array( 'responseModalities' => array( 'TEXT', 'IMAGE' ), 'imageConfig' => $image_config, ), ); $images = array(); for ( $i = 0; $i < $count; $i++ ) { $url = self::API_BASE . $model . ':generateContent?key=' . $api_key; $response = wp_remote_post( $url, array( 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( $body ), 'timeout' => 120, ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( 200 !== $code ) { $message = isset( $data['error']['message'] ) ? $data['error']['message'] : __( 'API request failed.', '45squared-ai-powered-image-generator' ); return new WP_Error( 'api_error', $message ); } $image_data = $this->extract_image_from_response( $data ); if ( is_wp_error( $image_data ) ) { return $image_data; } $images[] = $image_data; } return $images; } /** * Edit an existing image with a text prompt. * * @param string $image_path Absolute path to the source image. * @param string $prompt Edit instruction. * @param string $model Optional model override. * @return array|WP_Error Image data array or WP_Error. */ public function edit_image( $image_path, $prompt, $model = '' ) { $api_key = Nano_Banana_Settings::get_api_key(); if ( ! $api_key ) { return new WP_Error( 'no_api_key', __( 'API key is not configured.', '45squared-ai-powered-image-generator' ) ); } if ( ! file_exists( $image_path ) ) { return new WP_Error( 'file_not_found', __( 'Source image not found.', '45squared-ai-powered-image-generator' ) ); } if ( empty( $model ) ) { $model = get_option( 'nano_banana_model', 'gemini-3.1-flash-image-preview' ); } $image_bytes = file_get_contents( $image_path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents $mime_type = wp_check_filetype( $image_path )['type']; if ( ! $mime_type ) { $mime_type = 'image/png'; } $body = array( 'contents' => array( array( 'parts' => array( array( 'text' => $prompt ), array( 'inlineData' => array( 'mimeType' => $mime_type, 'data' => base64_encode( $image_bytes ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode ), ), ), ), ), 'generationConfig' => array( 'responseModalities' => array( 'TEXT', 'IMAGE' ), ), ); $url = self::API_BASE . $model . ':generateContent?key=' . $api_key; $response = wp_remote_post( $url, array( 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( $body ), 'timeout' => 120, ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); $data = json_decode( wp_remote_retrieve_body( $response ), true ); if ( 200 !== $code ) { $message = isset( $data['error']['message'] ) ? $data['error']['message'] : __( 'API request failed.', '45squared-ai-powered-image-generator' ); return new WP_Error( 'api_error', $message ); } return $this->extract_image_from_response( $data ); } /** * Test the API connection with a minimal request. * * @return true|WP_Error */ public function test_connection() { $api_key = Nano_Banana_Settings::get_api_key(); if ( ! $api_key ) { return new WP_Error( 'no_api_key', __( 'API key is not configured.', '45squared-ai-powered-image-generator' ) ); } $model = get_option( 'nano_banana_model', 'gemini-3.1-flash-image-preview' ); $url = self::API_BASE . $model . '?key=' . $api_key; $response = wp_remote_get( $url, array( 'timeout' => 30 ) ); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code( $response ); if ( 200 !== $code ) { $data = json_decode( wp_remote_retrieve_body( $response ), true ); $message = isset( $data['error']['message'] ) ? $data['error']['message'] : __( 'Connection failed.', '45squared-ai-powered-image-generator' ); return new WP_Error( 'connection_failed', $message ); } return true; } /** * Extract image binary data from a Gemini API response. * * @param array $response_data Decoded API response. * @return array|WP_Error { 'data' => binary, 'mime_type' => string } */ private function extract_image_from_response( $response_data ) { if ( empty( $response_data['candidates'][0]['content']['parts'] ) ) { return new WP_Error( 'no_image', __( 'No image returned by the API.', '45squared-ai-powered-image-generator' ) ); } foreach ( $response_data['candidates'][0]['content']['parts'] as $part ) { if ( isset( $part['inlineData'] ) ) { return array( 'data' => base64_decode( $part['inlineData']['data'] ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode 'mime_type' => $part['inlineData']['mimeType'], ); } } return new WP_Error( 'no_image', __( 'Response did not contain an image.', '45squared-ai-powered-image-generator' ) ); } /** * Save generated image data to the WordPress Media Library. * * @param array $image_data { 'data' => binary, 'mime_type' => string }. * @param string $prompt The prompt used to generate the image. * @param string $model The model used. * @return int|WP_Error Attachment ID or WP_Error. */ public function save_to_media_library( $image_data, $prompt, $model = '' ) { $ext = 'image/png' === $image_data['mime_type'] ? '.png' : '.jpg'; $filename = 'nano-banana-' . wp_generate_uuid4() . $ext; $upload = wp_upload_bits( $filename, null, $image_data['data'] ); if ( ! empty( $upload['error'] ) ) { return new WP_Error( 'upload_failed', $upload['error'] ); } // Ensure WP_Filesystem is initialized — required by some plugins // (e.g. WP Offload Media) that hook into attachment creation. if ( ! function_exists( 'WP_Filesystem' ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; } WP_Filesystem(); $attachment = array( 'post_title' => sanitize_text_field( wp_trim_words( $prompt, 10 ) ), 'post_content' => '', 'post_excerpt' => sanitize_textarea_field( $prompt ), 'post_status' => 'inherit', 'post_mime_type' => $image_data['mime_type'], ); $attach_id = wp_insert_attachment( $attachment, $upload['file'] ); if ( is_wp_error( $attach_id ) ) { return $attach_id; } require_once ABSPATH . 'wp-admin/includes/image.php'; $metadata = wp_generate_attachment_metadata( $attach_id, $upload['file'] ); wp_update_attachment_metadata( $attach_id, $metadata ); update_post_meta( $attach_id, '_nano_banana_prompt', sanitize_textarea_field( $prompt ) ); update_post_meta( $attach_id, '_nano_banana_model', sanitize_text_field( $model ) ); return $attach_id; } }