prefix . $t; $wpdb->query( "TRUNCATE TABLE {$table}" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- table name is $wpdb->prefix + a hardcoded literal; cannot be a bound parameter. } // Link-check transients. $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_transient\_aicitare_lnk2\_%' OR option_name LIKE '\_transient\_timeout\_aicitare_lnk2\_%'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter // Content blocks the plugin injected into posts. foreach ( array( '_aicitare_import_source', '_aicitare_rephrase_source', '_aicitare_faq', '_aicitare_pros', '_aicitare_cons', '_aicitare_table', '_aicitare_rating', '_aicitare_rating_count', '_aicitare_reviewer', '_aicitare_price', '_aicitare_currency' ) as $mk ) { delete_post_meta_by_key( $mk ); } // Re-seed a clean first-install state. add_option( AICITARE_OPT_PAGES, array() ); add_option( AICITARE_OPT_FIXED, array() ); add_option( AICITARE_OPT_BOTS, AICitare_Data::default_bots() ); add_option( AICITARE_OPT_SETTINGS, AICitare_Data::default_settings() ); AICitare_Log::add( 'reset', 'All plugin data reset to first-install state' ); } /** Custom table for real AI-crawler hit logging (mod_5 in the spec). */ public static function create_tables() { global $wpdb; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; $charset = $wpdb->get_charset_collate(); $table = $wpdb->prefix . 'aicitare_bot_hits'; $sql = "CREATE TABLE {$table} ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, bot_name VARCHAR(80) NOT NULL DEFAULT '', url VARCHAR(255) NOT NULL DEFAULT '', user_agent VARCHAR(255) NOT NULL DEFAULT '', ip VARCHAR(64) NOT NULL DEFAULT '', hit_at DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (id), KEY bot_name (bot_name), KEY hit_at (hit_at) ) {$charset};"; dbDelta( $sql ); $logs = $wpdb->prefix . 'aicitare_logs'; $sql2 = "CREATE TABLE {$logs} ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, action VARCHAR(60) NOT NULL DEFAULT '', detail VARCHAR(255) NOT NULL DEFAULT '', log_user VARCHAR(60) NOT NULL DEFAULT '', created_at DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (id), KEY created_at (created_at) ) {$charset};"; dbDelta( $sql2 ); $refs = $wpdb->prefix . 'aicitare_ai_refs'; $sql3 = "CREATE TABLE {$refs} ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, source VARCHAR(40) NOT NULL DEFAULT '', url VARCHAR(255) NOT NULL DEFAULT '', ref_at DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (id), KEY source (source), KEY ref_at (ref_at) ) {$charset};"; dbDelta( $sql3 ); } /** * DB/schema version. Bump when tables or rewrite rules change so existing * installs upgrade on the next admin load (activation hooks don't run on update). */ const DB_VERSION = '2'; /** Run pending migrations for already-active installs (called on plugins_loaded). */ public static function maybe_upgrade() { if ( get_option( 'aicitare_db_ver' ) === self::DB_VERSION ) { return; } self::create_tables(); flush_rewrite_rules(); update_option( 'aicitare_db_ver', self::DB_VERSION ); } }