'api_key', 'voice_id' => 'voice_id', 'voice_name' => 'voice_name', 'model' => 'model', 'mode' => 'processing_mode', 'post_types' => 'post_types', 'voices' => 'voices_list', 'chatgpt_api_key' => 'chatgpt_api_key', 'chatgpt_prompt' => 'chatgpt_prompt', ); /** * Default values. * * @since 1.0.0 * @var array */ private const DEFAULT_VALUES = array( 'api_key' => '', 'voice_id' => '', 'voice_name' => '', 'model' => 'eleven_multilingual_v2', 'mode' => 'wp_cron', 'post_types' => null, // Will be calculated dynamically. 'voices' => array(), 'chatgpt_api_key' => '', 'chatgpt_prompt' => '', ); /** * Get all saved settings with default values. * * @since 1.0.0 * @return array Array of saved settings. */ public function get_all_settings(): array { $settings = array(); foreach ( self::SETTINGS_MAPPING as $key => $option_suffix ) { $option_name = self::OPTION_PREFIX . $option_suffix; $default_value = $this->get_default_value( $key ); $settings[ $key ] = get_option( $option_name, $default_value ); } return $settings; } /** * Get specific setting value. * * @since 1.0.0 * @param string $setting_key Setting key. * @return mixed Setting value or default. */ public function get_setting( string $setting_key ) { if ( ! isset( self::SETTINGS_MAPPING[ $setting_key ] ) ) { return null; } $option_name = self::OPTION_PREFIX . self::SETTINGS_MAPPING[ $setting_key ]; $default_value = $this->get_default_value( $setting_key ); return get_option( $option_name, $default_value ); } /** * Save multiple settings. * * @since 1.0.0 * @param array $settings Settings array to save. * @return array Result with success status and any errors. */ public function save_settings( array $settings ): array { $results = array(); $errors = array(); foreach ( $settings as $key => $value ) { if ( ! isset( self::SETTINGS_MAPPING[ $key ] ) ) { /* translators: %s: invalid/unknown setting key */ $errors[ $key ] = sprintf( __( 'Unknown setting: %s', 'accessibility-audio-tts-text-to-speech-for-articles' ), $key ); continue; } $result = $this->save_setting( $key, $value ); $results[ $key ] = $result; if ( ! $result ) { /* translators: %s: setting key that failed to save */ $errors[ $key ] = sprintf( __( 'Failed to save setting: %s', 'accessibility-audio-tts-text-to-speech-for-articles' ), $key ); } } return array( 'success' => empty( $errors ), 'results' => $results, 'errors' => $errors, ); } /** * Save specific setting. * * @since 1.0.0 * @param string $setting_key Setting key. * @param mixed $value Setting value. * @return bool True if saved successfully. */ public function save_setting( string $setting_key, $value ): bool { if ( ! isset( self::SETTINGS_MAPPING[ $setting_key ] ) ) { return false; } $option_name = self::OPTION_PREFIX . self::SETTINGS_MAPPING[ $setting_key ]; return update_option( $option_name, $value ); } /** * Delete specific setting. * * @since 1.0.0 * @param string $setting_key Setting key. * @return bool True if deleted successfully. */ public function delete_setting( string $setting_key ): bool { if ( ! isset( self::SETTINGS_MAPPING[ $setting_key ] ) ) { return false; } $option_name = self::OPTION_PREFIX . self::SETTINGS_MAPPING[ $setting_key ]; return delete_option( $option_name ); } /** * Delete all plugin settings. * * @since 1.0.0 * @return array Results of deletion operations. */ public function delete_all_settings(): array { $results = array(); foreach ( self::SETTINGS_MAPPING as $key => $option_suffix ) { $option_name = self::OPTION_PREFIX . $option_suffix; $results[ $key ] = delete_option( $option_name ); } return $results; } /** * Check if settings are configured (have required values). * * @since 1.0.0 * @return bool True if settings are properly configured. */ public function are_settings_configured(): bool { $required_settings = array( 'api_key', 'voice_id', 'post_types' ); foreach ( $required_settings as $setting ) { $value = $this->get_setting( $setting ); if ( empty( $value ) ) { return false; } // Special check for post_types array. if ( 'post_types' === $setting && ( ! is_array( $value ) || empty( $value ) ) ) { return false; } } return true; } /** * Get settings that need configuration. * * @since 1.0.0 * @return array Array of missing or empty settings. */ public function get_missing_settings(): array { $required_settings = array( 'api_key', 'voice_id', 'post_types' ); $missing = array(); foreach ( $required_settings as $setting ) { $value = $this->get_setting( $setting ); if ( empty( $value ) ) { $missing[] = $setting; } elseif ( 'post_types' === $setting && ( ! is_array( $value ) || empty( $value ) ) ) { $missing[] = $setting; } } return $missing; } /** * Export settings for backup. * * @since 1.0.0 * @return array All settings data. */ public function export_settings(): array { $settings = $this->get_all_settings(); return array( 'version' => ACCESSIBILITY_AUDIO_TTS_VERSION, 'timestamp' => current_time( 'timestamp' ), // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested -- Intentional use for backup timestamp. 'settings' => $settings, ); } /** * Import settings from backup. * * @since 1.0.0 * @param array $import_data Import data. * @return array Import result. */ public function import_settings( array $import_data ): array { if ( ! isset( $import_data['settings'] ) || ! is_array( $import_data['settings'] ) ) { return array( 'success' => false, 'error' => __( 'Invalid import data format', 'accessibility-audio-tts-text-to-speech-for-articles' ), ); } $settings = $import_data['settings']; $result = $this->save_settings( $settings ); return array( 'success' => $result['success'], 'imported_count' => count( $settings ), 'errors' => $result['errors'] ?? array(), ); } /** * Get default value for setting. * * @since 1.0.0 * @param string $setting_key Setting key. * @return mixed Default value. */ private function get_default_value( string $setting_key ) { if ( 'post_types' === $setting_key ) { return $this->get_default_post_types(); } return self::DEFAULT_VALUES[ $setting_key ] ?? ''; } /** * Get default post types (excluding pages and attachments). * * @since 1.0.0 * @return array Default post types. */ private function get_default_post_types(): array { $all_post_types = get_post_types( array( 'public' => true ) ); return array_filter( $all_post_types, function ( $type ) { return ! in_array( $type, array( 'page', 'attachment' ), true ); } ); } /** * Get option name for setting. * * @since 1.0.0 * @param string $setting_key Setting key. * @return string|null Option name or null if invalid. */ public function get_option_name( string $setting_key ): ?string { if ( ! isset( self::SETTINGS_MAPPING[ $setting_key ] ) ) { return null; } return self::OPTION_PREFIX . self::SETTINGS_MAPPING[ $setting_key ]; } /** * Get all option names. * * @since 1.0.0 * @return array All option names. */ public function get_all_option_names(): array { $option_names = array(); foreach ( self::SETTINGS_MAPPING as $key => $option_suffix ) { $option_names[ $key ] = self::OPTION_PREFIX . $option_suffix; } return $option_names; } }