preg_replace( '/^sse_/', 'rafgrid_', (string) $tool ), (array) ( $settings['mcp_tools_denied'] ?? array() ) ); // Old builds stored a provider URL and model as defaults; keep them only when a key was entered. if ( empty( $settings['ai_api_key'] ) ) { $settings['ai_base_url'] = ''; $settings['ai_model'] = ''; } add_option( 'rafgrid_settings', $settings ); } foreach ( array( 'rules', 'redirects' ) as $name ) { $value = get_option( 'sse_' . $name, null ); if ( null !== $value && false === get_option( 'rafgrid_' . $name, false ) ) { add_option( 'rafgrid_' . $name, $value, '', false ); } } foreach ( array( 'settings', 'rules', 'redirects', 'version', 'mcp_key', 'mcp_log', 'presence', 'last_scheduled_export' ) as $name ) { delete_option( 'sse_' . $name ); } global $wpdb; // Finished or abandoned background job states (short-lived transients just expire). // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->options} WHERE option_name REGEXP %s", '^sse_job_j[0-9a-f]{10}$' ) ); } private static function tables() { global $wpdb; foreach ( array( 'history', 'audit' ) as $name ) { $old = $wpdb->prefix . 'sse_' . $name; $new = $wpdb->prefix . 'rafgrid_' . $name; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $has_old = $old === $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $old ) ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $has_new = $new === $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $new ) ) ); if ( $has_old && ! $has_new ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.DirectDatabaseQuery.SchemaChange -- One-time rename of this plugin's own tables. $wpdb->query( $wpdb->prepare( 'RENAME TABLE %i TO %i', $old, $new ) ); } } } private static function meta() { global $wpdb; // Per-user views, column layouts and presets: sse_* -> rafgrid_*. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->usermeta} SET meta_key = CONCAT( 'rafgrid_', SUBSTRING( meta_key, 5 ) ) WHERE meta_key LIKE %s OR meta_key LIKE %s OR meta_key = %s", $wpdb->esc_like( 'sse_views_' ) . '%', $wpdb->esc_like( 'sse_columns_' ) . '%', 'sse_presets' ) ); // Removed feature: personal MCP Bearer tokens (MCP now uses Application Passwords). // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->usermeta} WHERE meta_key = %s", '_sse_mcp_token_hash' ) ); // Team notes on items. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_key = %s WHERE meta_key = %s", '_rafgrid_notes', '_sse_notes' ) ); wp_cache_flush(); } private static function cron() { foreach ( array( 'sse_rules_run', 'sse_stock_alert', 'sse_scheduled_export', 'sse_bulk_job_chunk' ) as $hook ) { wp_unschedule_hook( $hook ); } if ( function_exists( 'as_unschedule_all_actions' ) ) { as_unschedule_all_actions( 'sse_bulk_job_chunk' ); } } /** * Old builds wrote snapshots and exports to public, predictable paths * (uploads/sse-snapshots, uploads/sse-exports). Move them into private storage. */ private static function files() { $uploads = wp_upload_dir( null, false ); $base = trailingslashit( $uploads['basedir'] ); foreach ( glob( $base . 'sse-snapshots/snapshot-*.json' ) ?: array() as $file ) { if ( preg_match( '/^snapshot-([a-z0-9_\-]+)-(\d{8}-\d{6})\.json$/', basename( $file ), $m ) ) { rename( $file, Storage::dir( 'snapshots' ) . 'snapshot-' . $m[1] . '-' . $m[2] . '-' . Storage::token() . '.json' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename } } foreach ( glob( $base . 'sse-exports/sheet-*.csv' ) ?: array() as $file ) { wp_delete_file( $file ); // Regenerated by the next scheduled run, now in private storage. } foreach ( array( 'sse-snapshots', 'sse-exports' ) as $dir ) { if ( is_dir( $base . $dir ) && ! ( glob( $base . $dir . '/*' ) ?: array() ) ) { rmdir( $base . $dir ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir } } } }