'array', 'sanitize_callback' => array( $this, 'sanitize_settings' ), 'default' => wpsco_get_default_settings(), ) ); } /** * Sanitize settings on save. * * @param array $input Raw input. * @return array */ public function sanitize_settings( $input ) { if ( ! is_array( $input ) ) { return wpsco_get_default_settings(); } $defaults = wpsco_get_default_settings(); $clean = array(); foreach ( $defaults as $key => $default_val ) { if ( ! isset( $input[ $key ] ) ) { if ( is_bool( $default_val ) ) { // Checkboxes not sent in POST are false. $clean[ $key ] = false; } else { $clean[ $key ] = $default_val; } continue; } $val = $input[ $key ]; if ( is_bool( $default_val ) ) { $clean[ $key ] = (bool) $val; } elseif ( is_int( $default_val ) ) { $clean[ $key ] = (int) $val; } elseif ( is_float( $default_val ) ) { $clean[ $key ] = (float) $val; } elseif ( is_array( $default_val ) ) { if ( is_array( $val ) ) { $clean[ $key ] = array_map( 'sanitize_text_field', $val ); } elseif ( is_string( $val ) ) { // Line-separated textarea. $lines = explode( "\n", str_replace( "\r", '', $val ) ); $clean[ $key ] = array_values( array_filter( array_map( 'sanitize_text_field', array_map( 'trim', $lines ) ) ) ); } else { $clean[ $key ] = $default_val; } } else { $clean[ $key ] = sanitize_text_field( $val ); } } // Increment cache version whenever settings change. wpsco_increment_cache_version(); // Trigger cache purge for generated CSS/JS/HTML. $plugin = WPSCO_Plugin::get_instance(); $purger = $plugin ? $plugin->get_module( 'cache_purger' ) : null; if ( $purger ) { $purger->purge_all(); } wpsco_log( 'Settings saved and caches invalidated.' ); return $clean; } /** * Apply Safe Mode preset. * * @return bool */ public static function apply_safe_mode() { $settings = wpsco_get_setting(); // Safe mode configuration: $settings['safe_mode'] = true; $settings['page_cache_enabled'] = true; $settings['css_minify'] = true; $settings['css_combine'] = false; // Keep false to avoid breaking layouts $settings['css_critical'] = false; $settings['css_remove_unused'] = false; // Never automatically remove selectors $settings['js_minify'] = false; // Keep false / safe in-memory $settings['js_combine'] = false; // Avoid JS ordering conflicts $settings['js_defer'] = false; $settings['js_delay'] = false; $settings['html_minify'] = true; $settings['lazy_load_images'] = true; $settings['lazy_load_iframes'] = true; $settings['add_missing_dimensions'] = true; $settings['font_display_swap'] = true; $settings['google_fonts_local'] = false; // Strictly opt-in to prevent external calls (Guideline 7) $settings['disable_emojis'] = true; $settings['remove_wp_version'] = true; $updated = update_option( self::OPTION_NAME, $settings ); wpsco_increment_cache_version(); return $updated; } /** * Apply One-Click Safe Optimization Wizard preset. * * @return bool */ public static function apply_one_click_safe_optimization() { $settings = wpsco_get_setting(); $settings['safe_mode'] = true; $settings['page_cache_enabled'] = true; $settings['page_cache_ttl'] = 3600; $settings['css_minify'] = true; $settings['css_combine'] = false; $settings['css_async'] = true; // Asynchronous non-blocking CSS delivery $settings['js_minify'] = false; // Safe in-memory optimization only when explicitly toggled $settings['js_defer'] = true; $settings['js_delay'] = true; // Eliminates TBT on mobile $settings['js_delay_timeout'] = 3; $settings['js_delay_trigger'] = 'interaction'; $settings['html_minify'] = true; $settings['lazy_load_images'] = true; $settings['lazy_load_iframes'] = true; $settings['lazy_load_youtube'] = true; $settings['add_missing_dimensions'] = true; // Eliminates CLS $settings['lcp_image_preload'] = true; // Optimizes LCP $settings['webp_conversion'] = true; // Next-gen image format $settings['image_compression'] = true; // Lossless compression $settings['font_display_swap'] = true; // Eliminates FOIT $settings['google_fonts_local'] = false; // Disabled by default to prevent automatic external requests (Guideline 7) $settings['disable_emojis'] = true; $settings['disable_embeds'] = true; $settings['remove_wp_version'] = true; $settings['delay_analytics'] = true; $settings['delay_gtm'] = true; $settings['delay_facebook_pixel'] = true; $settings['delay_clarity'] = true; $settings['browser_cache_htaccess'] = true; $settings['compression_htaccess'] = true; $updated = update_option( self::OPTION_NAME, $settings ); wpsco_increment_cache_version(); return $updated; } /** * Reset settings to default. * * @return bool */ public static function reset_to_defaults() { $defaults = wpsco_get_default_settings(); $updated = update_option( self::OPTION_NAME, $defaults ); wpsco_increment_cache_version(); $plugin = WPSCO_Plugin::get_instance(); $purger = $plugin ? $plugin->get_module( 'cache_purger' ) : null; if ( $purger ) { $purger->purge_everything(); } return $updated; } /** * Export settings as JSON string. * * @return string */ public static function export_json() { $settings = wpsco_get_setting(); // Redact secret API keys on export. $export = $settings; $export['cloudflare_api_token'] = ''; $export['cdn_api_key'] = ''; $export['export_version'] = WPSCO_VERSION; $export['exported_at'] = gmdate( 'Y-m-d H:i:s' ); return wp_json_encode( $export, JSON_PRETTY_PRINT ); } /** * Import settings from JSON string. * * @param string $json JSON payload. * @return bool|WP_Error */ public static function import_json( $json ) { $data = json_decode( $json, true ); if ( ! is_array( $data ) ) { return new WP_Error( 'invalid_json', __( 'Invalid JSON format for settings import.', 'speednest' ) ); } unset( $data['export_version'], $data['exported_at'] ); $defaults = wpsco_get_default_settings(); $merged = wp_parse_args( $data, $defaults ); // Sanitize before saving. $sanitizer = new self(); $clean = $sanitizer->sanitize_settings( $merged ); update_option( self::OPTION_NAME, $clean ); wpsco_increment_cache_version(); return true; } }