> */ private const FIELDS = array( 'layout' => array( 'type' => 'enum', 'values' => array( 'command', 'cards', 'list' ), 'default' => 'command', 'public' => true, ), 'theme' => array( 'type' => 'enum', 'values' => array( 'light', 'dark' ), 'default' => 'dark', 'public' => true, ), 'palette' => array( 'type' => 'enum', 'values' => array( 'midnight', 'ocean', 'ember', 'forest', 'light' ), 'default' => 'midnight', 'public' => true, ), 'refresh_interval' => array( 'type' => 'int', 'min' => self::MIN_REFRESH_MINUTES, 'max' => 1440, 'default' => 15, 'public' => false, ), 'max_items' => array( 'type' => 'int', 'min' => 5, 'max' => 100, 'default' => 30, 'public' => true, ), 'show_source' => array( 'type' => 'bool', 'default' => true, 'public' => true, ), 'show_time' => array( 'type' => 'bool', 'default' => true, 'public' => true, ), 'show_images' => array( 'type' => 'bool', 'default' => true, 'public' => true, ), 'headlines_heading' => array( 'type' => 'text', 'max' => 40, 'default' => 'Latest Headlines', 'public' => true, ), 'show_headlines_heading' => array( 'type' => 'bool', 'default' => true, 'public' => true, ), ); /** * Default value for every setting. * * @return array */ public static function defaults(): array { return array_map( static fn( array $field ) => $field['default'], self::FIELDS ); } /** * Validates input into a complete settings array. * * Unknown keys are dropped. Missing, wrongly typed and invalid values fall back to the * default. Integers are clamped to their allowed range. * * @param array $input Raw settings. * @return array */ public static function sanitize( array $input ): array { $clean = array(); foreach ( self::FIELDS as $name => $field ) { $clean[ $name ] = self::sanitize_value( $field, $input[ $name ] ?? null ); } // Dashboards saved before palettes existed only have a theme. Derive the palette from it, and // keep `theme` (dark or light) consistent with the palette for anything that still reads it. if ( ! in_array( $input['palette'] ?? null, self::FIELDS['palette']['values'], true ) ) { $clean['palette'] = 'light' === $clean['theme'] ? 'light' : 'midnight'; } $clean['theme'] = 'light' === $clean['palette'] ? 'light' : 'dark'; return $clean; } /** * The settings that may be shown to anonymous visitors. * * @param array $settings Settings, validated first. * @return array */ public static function public_settings( array $settings ): array { $settings = self::sanitize( $settings ); $public = array(); foreach ( self::FIELDS as $name => $field ) { if ( $field['public'] ) { $public[ $name ] = $settings[ $name ]; } } return $public; } /** * Validates one value against its field declaration. * * @param array $field Field declaration. * @param mixed $value Raw value. * @return mixed */ private static function sanitize_value( array $field, $value ) { switch ( $field['type'] ) { case 'enum': return ( is_string( $value ) && in_array( $value, $field['values'], true ) ) ? $value : $field['default']; case 'int': if ( is_int( $value ) || ( is_string( $value ) && 1 === preg_match( '/^-?\d{1,9}$/', $value ) ) ) { return max( $field['min'], min( $field['max'], (int) $value ) ); } return $field['default']; case 'text': $text = is_string( $value ) ? Feed_Normalizer::plain_text( $value, $field['max'] ) : ''; return '' !== $text ? $text : $field['default']; case 'bool': $bool = is_bool( $value ) || is_int( $value ) || is_string( $value ) ? filter_var( $value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ) : null; return $bool ?? $field['default']; }//end switch return $field['default']; } }