default. */ const DEFAULTS = array( 'enabled' => true, 'sample_rate' => 5, 'track_ajax' => true, 'track_admin' => false, 'retention_days' => 30, 'slow_threshold_ms' => 700, 'detail_threshold_ms' => 300, 'excluded_paths' => '', 'delete_on_uninstall' => false, ); /** * Setting => array( min, max ) for integers. */ const LIMITS = array( 'sample_rate' => array( 1, 1000 ), 'retention_days' => array( 1, 365 ), 'slow_threshold_ms' => array( 50, 60000 ), 'detail_threshold_ms' => array( 0, 60000 ), ); /** * Cached settings for the request. * * @var array|null */ private static ?array $cache = null; /** * All settings merged over the defaults. */ public static function all(): array { if ( null === self::$cache ) { $stored = get_option( self::OPTION, array() ); self::$cache = array_merge( self::DEFAULTS, is_array( $stored ) ? $stored : array() ); } return self::$cache; } /** * One setting. * * @param string $key Setting name. * * @return mixed */ public static function get( string $key ) { return self::all()[ $key ] ?? null; } /** * Validate and save settings from user input. * * @param array $input Raw input. * * @return array Saved settings. */ public static function save( array $input ): array { $clean = self::all(); foreach ( self::DEFAULTS as $key => $default ) { if ( ! array_key_exists( $key, $input ) ) { continue; } if ( is_bool( $default ) ) { $clean[ $key ] = filter_var( $input[ $key ], FILTER_VALIDATE_BOOLEAN ); } elseif ( is_int( $default ) ) { [ $min, $max ] = self::LIMITS[ $key ]; $clean[ $key ] = min( $max, max( $min, (int) $input[ $key ] ) ); } else { $clean[ $key ] = sanitize_textarea_field( (string) $input[ $key ] ); } } update_option( self::OPTION, $clean, false ); self::$cache = $clean; return $clean; } /** * Store defaults on first activation. */ public static function ensure_defaults(): void { if ( false === get_option( self::OPTION ) ) { add_option( self::OPTION, self::DEFAULTS, '', false ); } } /** * Excluded path prefixes, one per line. * * @return string[] */ public static function excluded_paths(): array { return array_values( array_filter( array_map( 'trim', explode( "\n", (string) self::get( 'excluded_paths' ) ) ) ) ); } }