*/ private const REQUIRED_KEYS = array( 'host', 'key', 'secret', 'bucket', 'region', ); /** * WordPress option name for settings. * * @var string */ private const OPTION_NAME = 'idrivee2_media_settings'; /** * Map of config keys to wp-config.php constant names. * * Centralised so is_defined_in_wp_config() and get_value() cannot drift. * * @since 1.3.0 * * @var array */ private const CONSTANT_MAP = array( 'host' => 'IDRIVEE2_MEDIA_HOST', 'key' => 'IDRIVEE2_MEDIA_KEY', 'secret' => 'IDRIVEE2_MEDIA_SECRET', 'bucket' => 'IDRIVEE2_MEDIA_BUCKET', 'region' => 'IDRIVEE2_MEDIA_REGION', 'domain' => 'IDRIVEE2_MEDIA_DOMAIN', 'subsizes_mode' => 'IDRIVEE2_MEDIA_SUBSIZES_MODE', ); /** * Logger instance. * * @var Logger|null */ private $logger; /** * Constructor. * * @since 0.3.1 * * @param Logger|null $logger Optional logger instance. */ public function __construct( ?Logger $logger = null ) { $this->logger = $logger; } /** * Check if all required configuration values are available. * * Checks both wp-config.php constants and WordPress options. * * @since 0.3.0 * * @return bool True if all required values are available, false otherwise. */ public function is_configured(): bool { foreach ( self::REQUIRED_KEYS as $key ) { $value = $this->get_value( $key ); if ( empty( $value ) ) { return false; } } return true; } /** * Check if a configuration key is defined in wp-config.php. * * @since 0.3.0 * * @param string $key Configuration key (host, key, secret, bucket, region, domain). * @return bool True if defined in wp-config.php, false otherwise. */ public function is_defined_in_wp_config( string $key ): bool { $constant_name = self::CONSTANT_MAP[ $key ] ?? ''; return '' !== $constant_name && defined( $constant_name ); } /** * Get a configuration value. * * Priority: wp-config.php constants first, then WordPress options. * * @since 0.3.0 * * @param string $key Configuration key (host, key, secret, bucket, region, domain). * @return string The configuration value, or empty string if not set. */ private function get_value( string $key ): string { // Check wp-config.php constant first (highest priority). $constant_name = self::CONSTANT_MAP[ $key ] ?? ''; if ( '' !== $constant_name && defined( $constant_name ) ) { return (string) constant( $constant_name ); } // Fall back to WordPress option. $options = get_option( self::OPTION_NAME, array() ); if ( ! is_array( $options ) ) { return ''; } return isset( $options[ $key ] ) && is_string( $options[ $key ] ) ? $options[ $key ] : ''; } /** * Get the S3 endpoint host URL. * * @since 0.3.0 * * @return string The S3 endpoint URL. */ public function get_host(): string { return $this->get_value( 'host' ); } /** * Get the S3 access key ID. * * @since 0.3.0 * * @return string The access key ID. */ public function get_key(): string { return $this->get_value( 'key' ); } /** * Get the S3 secret access key. * * @since 0.3.0 * * @return string The secret access key. */ public function get_secret(): string { return $this->get_value( 'secret' ); } /** * Get the S3 bucket name. * * @since 0.3.0 * * @return string The bucket name. */ public function get_bucket(): string { return $this->get_value( 'bucket' ); } /** * Get the AWS region. * * @since 0.3.0 * * @return string The AWS region. */ public function get_region(): string { return $this->get_value( 'region' ); } /** * Get the custom CDN domain, if defined. * * @since 0.3.0 * * @return string The custom domain, or empty string if not defined. */ public function get_domain(): string { return $this->get_value( 'domain' ); } /** * Check if a custom CDN domain is defined. * * @since 0.3.0 * * @return bool True if domain is defined and non-empty. */ public function has_domain(): bool { return ! empty( $this->get_domain() ); } /** * Get the configured sub-sizes mode. * * Controls which image sub-sizes WordPress generates. Returns one of * 'all', 'thumbnail', or 'none'; falls back to 'all' for any value that * is not on the whitelist (including unset/empty). * * @since 1.3.0 * * @return string The sub-sizes mode. */ public function get_subsizes_mode(): string { $value = $this->get_value( 'subsizes_mode' ); $allowed = array( 'all', 'thumbnail', 'none', ); return in_array( $value, $allowed, true ) ? $value : 'all'; } /** * Check if the user opted in to delete all data on uninstall. * * @since 1.4.0 * * @return bool True if all plugin data should be removed on uninstall. */ public function is_delete_on_uninstall(): bool { $options = get_option( self::OPTION_NAME, array() ); return is_array( $options ) && isset( $options['delete_on_uninstall'] ) && '1' === $options['delete_on_uninstall']; } /** * Update configuration options in WordPress database. * * @since 0.3.0 * * @param array $data Configuration data to save. * @return bool True on success, false on failure. */ public function update_options( array $data ): bool { // Get current options for comparison. $raw_old = get_option( self::OPTION_NAME, array() ); $old_options = is_array( $raw_old ) ? $raw_old : array(); // Validate and sanitize data. $options = array( 'host' => isset( $data['host'] ) ? sanitize_text_field( $data['host'] ) : '', 'key' => isset( $data['key'] ) ? sanitize_text_field( $data['key'] ) : '', 'secret' => isset( $data['secret'] ) ? sanitize_text_field( $data['secret'] ) : '', 'bucket' => isset( $data['bucket'] ) ? sanitize_text_field( $data['bucket'] ) : '', 'region' => isset( $data['region'] ) ? sanitize_text_field( $data['region'] ) : '', 'domain' => isset( $data['domain'] ) ? sanitize_text_field( $data['domain'] ) : '', ); // Sub-sizes mode: strict whitelist, default 'all'. $raw_mode = isset( $data['subsizes_mode'] ) ? strtolower( (string) sanitize_text_field( $data['subsizes_mode'] ) ) : ''; $allowed_modes = array( 'all', 'thumbnail', 'none' ); $options['subsizes_mode'] = in_array( $raw_mode, $allowed_modes, true ) ? $raw_mode : 'all'; // Data cleanup on uninstall: checkbox, default off (preserve data). $options['delete_on_uninstall'] = ! empty( $data['delete_on_uninstall'] ) ? '1' : ''; // Log configuration changes. if ( $this->logger ) { foreach ( $options as $key => $new_value ) { $old_value = isset( $old_options[ $key ] ) && is_string( $old_options[ $key ] ) ? $old_options[ $key ] : ''; if ( $old_value !== $new_value ) { $this->logger->config_change( $key, $old_value, $new_value ); } } } return update_option( self::OPTION_NAME, $options ); } }