Settings -> Forms), option reactwoo_atomic_forms. * * Turnstile keys and the global blocklist are used by the Pro anti-spam layer only; the store * lives in the shared forms package so the settings screen can read it on both editions. * The secret is never printed back: the screen shows whether one is saved and keeps it when the * field is left empty. * * @package ReactWoo\Atomic */ namespace ReactWoo\Atomic\Forms; defined( 'ABSPATH' ) || exit; final class Forms_Settings { const OPTION = 'reactwoo_atomic_forms'; const SUMMARY_DEFAULT_MINUTES = 30; const SUMMARY_MIN_MINUTES = 5; const SUMMARY_MAX_MINUTES = 1440; /** * @return array{turnstile_site_key:string,turnstile_secret:string,blocklist:string,summary_link_minutes:string,summary_single_use:string} */ public static function defaults() { return array( 'turnstile_site_key' => '', 'turnstile_secret' => '', 'blocklist' => '', 'summary_link_minutes' => (string) self::SUMMARY_DEFAULT_MINUTES, 'summary_single_use' => '0', ); } /** * @return array{turnstile_site_key:string,turnstile_secret:string,blocklist:string,summary_link_minutes:string,summary_single_use:string} */ public static function all() { $row = get_option( self::OPTION, array() ); $row = is_array( $row ) ? $row : array(); $out = self::defaults(); foreach ( $out as $k => $v ) { if ( isset( $row[ $k ] ) && is_string( $row[ $k ] ) ) { $out[ $k ] = $row[ $k ]; } } return $out; } /** * @param string $key Key. * @return string */ public static function get( $key ) { $all = self::all(); return isset( $all[ $key ] ) ? (string) $all[ $key ] : ''; } /** * Lifetime of the reactwoo_atomic_s answer-summary link, in minutes (5 - 1440, default 30). * * @return int */ public static function summary_link_minutes() { return self::clamp_minutes( self::get( 'summary_link_minutes' ) ); } /** * Single-use answer-summary links: the token stops working after the first successful fetch. * * @return bool */ public static function summary_single_use() { return '1' === self::get( 'summary_single_use' ); } /** * @param mixed $v Raw minutes. * @return int */ private static function clamp_minutes( $v ) { $n = is_numeric( $v ) ? (int) $v : self::SUMMARY_DEFAULT_MINUTES; return max( self::SUMMARY_MIN_MINUTES, min( self::SUMMARY_MAX_MINUTES, $n ) ); } /** * Turnstile is usable only with both keys. */ public static function turnstile_ready() { return '' !== self::get( 'turnstile_site_key' ) && '' !== self::get( 'turnstile_secret' ); } /** * @param array $input Raw POST (unslashed). * @return array */ public static function sanitize( array $input ) { $out = self::all(); if ( isset( $input['reactwoo_atomic_forms_turnstile_site_key'] ) ) { $out['turnstile_site_key'] = self::clean_key( $input['reactwoo_atomic_forms_turnstile_site_key'] ); } if ( ! empty( $input['reactwoo_atomic_forms_turnstile_secret_clear'] ) ) { $out['turnstile_secret'] = ''; } elseif ( isset( $input['reactwoo_atomic_forms_turnstile_secret'] ) && '' !== trim( (string) $input['reactwoo_atomic_forms_turnstile_secret'] ) ) { $out['turnstile_secret'] = self::clean_key( $input['reactwoo_atomic_forms_turnstile_secret'] ); } if ( isset( $input['reactwoo_atomic_forms_blocklist'] ) ) { $lines = preg_split( '/[\r\n,]+/', (string) $input['reactwoo_atomic_forms_blocklist'] ); $lines = array_slice( array_values( array_unique( array_filter( array_map( static function ( $l ) { return substr( trim( sanitize_text_field( $l ) ), 0, 200 ); }, (array) $lines ) ) ) ), 0, 500 ); $out['blocklist'] = implode( "\n", $lines ); } if ( isset( $input['reactwoo_atomic_forms_summary_link_minutes'] ) ) { $out['summary_link_minutes'] = (string) self::clamp_minutes( $input['reactwoo_atomic_forms_summary_link_minutes'] ); } if ( isset( $input['reactwoo_atomic_forms_summary_single_use_present'] ) || isset( $input['reactwoo_atomic_forms_summary_single_use'] ) ) { $out['summary_single_use'] = ! empty( $input['reactwoo_atomic_forms_summary_single_use'] ) ? '1' : '0'; } return $out; } /** * @param array $input Raw POST (unslashed). * @return void */ public static function save( array $input ) { $clean = self::sanitize( $input ); if ( self::all() !== $clean ) { update_option( self::OPTION, $clean, false ); } } /** * @param mixed $v Raw key. * @return string */ private static function clean_key( $v ) { return substr( preg_replace( '/[^A-Za-z0-9_\-.]/', '', (string) $v ), 0, 200 ); } }