'Nano Banana (Fast)', 'gemini-3-pro-image-preview' => 'Nano Banana Pro (High Quality)', 'gemini-3.1-flash-image-preview' => 'Nano Banana 2 (Balanced)', ); const ASPECT_RATIOS = array( '1:1' => '1:1 (Square)', '16:9' => '16:9 (Landscape)', '9:16' => '9:16 (Portrait)', '4:3' => '4:3 (Standard)', '3:2' => '3:2 (Photo)', ); const IMAGE_SIZES = array( '512' => '512px', '1K' => '1K (1024px)', '2K' => '2K (2048px)', '4K' => '4K (4096px)', ); /** * Hook into WordPress. */ public function init() { add_action( 'admin_menu', array( $this, 'add_menu_page' ) ); add_action( 'admin_init', array( $this, 'register_settings' ) ); add_action( 'wp_ajax_nano_banana_test_connection', array( $this, 'ajax_test_connection' ) ); } /** * Register the settings page under Settings. */ public function add_menu_page() { add_options_page( __( 'Nano Banana Settings', '45squared-ai-powered-image-generator' ), __( 'Nano Banana', '45squared-ai-powered-image-generator' ), 'manage_options', 'nano-banana', array( $this, 'render_settings_page' ) ); } /** * Register settings fields. */ public function register_settings() { register_setting( 'nano_banana_settings', 'nano_banana_api_key', array( 'type' => 'string', 'sanitize_callback' => array( $this, 'sanitize_api_key' ), ) ); register_setting( 'nano_banana_settings', 'nano_banana_model', array( 'type' => 'string', 'default' => 'gemini-3.1-flash-image-preview', 'sanitize_callback' => array( $this, 'sanitize_model' ), ) ); register_setting( 'nano_banana_settings', 'nano_banana_default_aspect_ratio', array( 'type' => 'string', 'default' => '1:1', 'sanitize_callback' => array( $this, 'sanitize_aspect_ratio' ), ) ); add_settings_section( 'nano_banana_main', __( 'API Configuration', '45squared-ai-powered-image-generator' ), array( $this, 'render_section_description' ), 'nano-banana' ); add_settings_field( 'nano_banana_api_key', __( 'Google AI API Key', '45squared-ai-powered-image-generator' ), array( $this, 'render_api_key_field' ), 'nano-banana', 'nano_banana_main' ); add_settings_field( 'nano_banana_model', __( 'Default Model', '45squared-ai-powered-image-generator' ), array( $this, 'render_model_field' ), 'nano-banana', 'nano_banana_main' ); add_settings_field( 'nano_banana_default_aspect_ratio', __( 'Default Aspect Ratio', '45squared-ai-powered-image-generator' ), array( $this, 'render_aspect_ratio_field' ), 'nano-banana', 'nano_banana_main' ); register_setting( 'nano_banana_settings', 'nano_banana_default_image_size', array( 'type' => 'string', 'default' => '1K', 'sanitize_callback' => array( $this, 'sanitize_image_size' ), ) ); add_settings_field( 'nano_banana_default_image_size', __( 'Default Image Size', '45squared-ai-powered-image-generator' ), array( $this, 'render_image_size_field' ), 'nano-banana', 'nano_banana_main' ); } /** * Encrypt the API key before storage. * * @param string $value Raw API key. * @return string Encrypted key. */ public function sanitize_api_key( $value ) { $value = sanitize_text_field( $value ); if ( empty( $value ) ) { return ''; } // Don't re-encrypt the masked placeholder — keep existing key. if ( str_repeat( "\u{2022}", 16 ) === $value ) { return get_option( 'nano_banana_api_key', '' ); } // Guard against double encryption: on first save, update_option() // sanitizes the value and then falls through to add_option() which // sanitizes again. If the value already decrypts successfully, it // was already encrypted by a prior pass — return it as-is. $decrypted = self::decrypt( $value ); if ( false !== $decrypted ) { return $value; } return self::encrypt( $value ); } /** * Validate model selection. * * @param string $value Model ID. * @return string */ public function sanitize_model( $value ) { return array_key_exists( $value, self::MODELS ) ? $value : 'gemini-3.1-flash-image-preview'; } /** * Validate aspect ratio selection. * * @param string $value Aspect ratio. * @return string */ public function sanitize_aspect_ratio( $value ) { return array_key_exists( $value, self::ASPECT_RATIOS ) ? $value : '1:1'; } /** * Validate image size selection. * * @param string $value Image size. * @return string */ public function sanitize_image_size( $value ) { return array_key_exists( $value, self::IMAGE_SIZES ) ? $value : '1K'; } /** * Render the settings page. */ public function render_settings_page() { if ( ! current_user_can( 'manage_options' ) ) { return; } ?>
' . esc_html__( 'Google AI pricing', '45squared-ai-powered-image-generator' ) . '' ); ?>
test_connection(); if ( is_wp_error( $result ) ) { wp_send_json_error( $result->get_error_message() ); } set_transient( 'nano_banana_connection_test', 'ok', HOUR_IN_SECONDS ); wp_send_json_success( __( 'Connection successful!', '45squared-ai-powered-image-generator' ) ); } /** * Get the decrypted API key. * * @return string|false Decrypted key or false if not set. */ public static function get_api_key() { $encrypted = get_option( 'nano_banana_api_key', '' ); if ( empty( $encrypted ) ) { return false; } return self::decrypt( $encrypted ); } /** * Encrypt a value using OpenSSL. * * @param string $value Plain text value. * @return string Base64-encoded encrypted value. */ private static function encrypt( $value ) { $key = self::get_encryption_key(); $iv = openssl_random_pseudo_bytes( 16 ); $cipher = openssl_encrypt( $value, 'aes-256-cbc', $key, 0, $iv ); return base64_encode( $iv . '::' . $cipher ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode } /** * Decrypt a value. * * @param string $value Base64-encoded encrypted value. * @return string|false Decrypted value or false on failure. */ private static function decrypt( $value ) { $key = self::get_encryption_key(); $data = base64_decode( $value ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode if ( false === $data || false === strpos( $data, '::' ) ) { return false; } list( $iv, $cipher ) = explode( '::', $data, 2 ); return openssl_decrypt( $cipher, 'aes-256-cbc', $key, 0, $iv ); } /** * Get or generate the encryption key. * * @return string */ private static function get_encryption_key() { if ( defined( 'NANO_BANANA_ENCRYPTION_KEY' ) ) { return NANO_BANANA_ENCRYPTION_KEY; } $key = get_option( 'nano_banana_encryption_key' ); if ( ! $key ) { $key = wp_generate_password( 64, true, true ); add_option( 'nano_banana_encryption_key', $key ); } return $key; } }