'gemini-2.5-flash', 'site_concept' => '', 'output_language' => 'auto', 'sample_posts' => 10, 'sync_seo_meta' => 1, 'draft_category' => 1, 'create_categories' => 0, 'fix_link_anchors' => 1, ); } /** * Create the settings row if it does not exist yet. */ public static function install_defaults() { if ( false === get_option( self::OPTION, false ) ) { add_option( self::OPTION, self::defaults() ); } } /** * All settings, with defaults filled in. * * @return array */ public static function all() { $stored = get_option( self::OPTION, array() ); if ( ! is_array( $stored ) ) { $stored = array(); } return array_merge( self::defaults(), $stored ); } /** * One setting. * * @param string $key Setting name. * @param mixed $default Value to use when the setting is missing. * @return mixed */ public static function get( $key, $default = '' ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.defaultFound -- Public method; renaming the parameter would break callers that use named arguments. $all = self::all(); return array_key_exists( $key, $all ) ? $all[ $key ] : $default; } /** * Replace the whole settings row with a sanitised version of the input. * * Unknown keys are dropped, every value is forced into the shape the * plugin expects, and anything unusable falls back to the default. * * @param array $input Raw values. * @return array The values that were stored. */ public static function save( $input ) { $defaults = self::defaults(); $clean = $defaults; if ( ! is_array( $input ) ) { update_option( self::OPTION, $clean ); return $clean; } if ( isset( $input['model'] ) ) { $model = sanitize_text_field( (string) $input['model'] ); if ( array_key_exists( $model, self::models() ) ) { $clean['model'] = $model; } } if ( isset( $input['site_concept'] ) ) { $clean['site_concept'] = mb_substr( sanitize_textarea_field( (string) $input['site_concept'] ), 0, 2000 ); } if ( isset( $input['output_language'] ) ) { $language = sanitize_text_field( (string) $input['output_language'] ); if ( array_key_exists( $language, self::languages() ) ) { $clean['output_language'] = $language; } } if ( isset( $input['sample_posts'] ) ) { $samples = absint( $input['sample_posts'] ); if ( $samples >= 3 && $samples <= 30 ) { $clean['sample_posts'] = $samples; } } $clean['sync_seo_meta'] = ( isset( $input['sync_seo_meta'] ) && '1' === (string) $input['sync_seo_meta'] ) ? 1 : 0; $clean['draft_category'] = ( isset( $input['draft_category'] ) && '1' === (string) $input['draft_category'] ) ? 1 : 0; $clean['create_categories'] = ( isset( $input['create_categories'] ) && '1' === (string) $input['create_categories'] ) ? 1 : 0; $clean['fix_link_anchors'] = ( isset( $input['fix_link_anchors'] ) && '1' === (string) $input['fix_link_anchors'] ) ? 1 : 0; update_option( self::OPTION, $clean ); return $clean; } /** * The Gemini models offered in the settings screen. * * @return array Model id => label. */ public static function models() { return array( 'gemini-2.5-flash' => 'Gemini 2.5 Flash', 'gemini-2.5-flash-lite' => 'Gemini 2.5 Flash-Lite', 'gemini-2.5-pro' => 'Gemini 2.5 Pro', 'gemini-3.5-flash' => 'Gemini 3.5 Flash', 'gemini-3.6-flash' => 'Gemini 3.6 Flash', ); } /** * Languages the article can be written in. * * @return array Value => label. */ public static function languages() { return array( 'auto' => __( 'Same language as this site', 'acs-article-generator' ), 'ja' => __( 'Japanese', 'acs-article-generator' ), 'en' => __( 'English', 'acs-article-generator' ), 'es' => __( 'Spanish', 'acs-article-generator' ), 'fr' => __( 'French', 'acs-article-generator' ), 'de' => __( 'German', 'acs-article-generator' ), 'it' => __( 'Italian', 'acs-article-generator' ), 'pt' => __( 'Portuguese', 'acs-article-generator' ), 'nl' => __( 'Dutch', 'acs-article-generator' ), 'ko' => __( 'Korean', 'acs-article-generator' ), 'zh' => __( 'Chinese', 'acs-article-generator' ), 'ru' => __( 'Russian', 'acs-article-generator' ), 'id' => __( 'Indonesian', 'acs-article-generator' ), ); } /** * The plain language name handed to the model, resolved from the setting * or, for "auto", from the site locale. * * @return string */ public static function language_for_prompt() { $names = array( 'ja' => 'Japanese', 'en' => 'English', 'es' => 'Spanish', 'fr' => 'French', 'de' => 'German', 'it' => 'Italian', 'pt' => 'Portuguese', 'nl' => 'Dutch', 'ko' => 'Korean', 'zh' => 'Chinese', 'ru' => 'Russian', 'id' => 'Indonesian', ); $choice = (string) self::get( 'output_language', 'auto' ); if ( 'auto' !== $choice && isset( $names[ $choice ] ) ) { return $names[ $choice ]; } $locale = strtolower( (string) get_locale() ); $code = substr( $locale, 0, 2 ); if ( isset( $names[ $code ] ) ) { return $names[ $code ]; } return 'the same language as the existing posts on this site'; } /** * Whether an API key has been saved. * * @return bool */ public static function has_api_key() { return '' !== self::api_key(); } /** * The stored API key. * * This value is never printed to the screen, never written to a log and * never included in an error message. It is read here and handed straight * to the request header. * * @return string */ public static function api_key() { return trim( (string) get_option( self::OPTION_KEY, '' ) ); } /** * Store an API key in its own non-autoloaded row. * * @param string $key Raw key. */ public static function save_api_key( $key ) { $key = trim( sanitize_text_field( (string) $key ) ); if ( '' === $key ) { return; } if ( false === get_option( self::OPTION_KEY, false ) ) { add_option( self::OPTION_KEY, $key, '', 'no' ); return; } update_option( self::OPTION_KEY, $key, 'no' ); } /** * Forget the stored API key. */ public static function delete_api_key() { delete_option( self::OPTION_KEY ); } }