| @@ -38,8 +38,9 @@ | ||
| 38 | 38 | $this->remove_caps(); |
| 39 | 39 | $this->remove_post_data(); |
| 40 | 40 | $this->remove_tables(); |
| 41 | 41 | $this->remove_settings(); |
| 42 | + $this->remove_abilities_data(); | |
| 42 | 43 | |
| 43 | 44 | do_action( 'charitable_uninstall' ); |
| 44 | 45 | } |
| 45 | 46 | } |
| @@ -122,8 +123,57 @@ | ||
| 122 | 123 | |
| 123 | 124 | /* Stop Charitable from re-adding the notices transient. */ |
| 124 | 125 | if ( function_exists( 'charitable_get_admin_notices' ) ) { |
| 125 | 126 | remove_action( 'shutdown', array( charitable_get_admin_notices(), 'shutdown' ) ); |
| 127 | + } | |
| 128 | + | |
| 129 | + /* | |
| 130 | + * The `ai_mcp_write_enabled` setting (Charitable_Tools_Ai_Mcp::WRITE_SETTING_KEY) | |
| 131 | + * needs NO separate delete_option() call. It is not its own option - | |
| 132 | + * it is a key nested inside the `charitable_settings` array, written by | |
| 133 | + * ajax_toggle_write() as $settings['ai_mcp_write_enabled'], and the | |
| 134 | + * blanket delete_option( 'charitable_settings' ) above already removes | |
| 135 | + * it. Any future AI setting nested the same way needs no change here | |
| 136 | + * either. (1.8.13 briefly also stored `ai_mcp_write_scopes` in that | |
| 137 | + * array; it was removed before release, and the blanket delete covered | |
| 138 | + * it while it existed.) | |
| 139 | + * | |
| 140 | + * @since 1.8.13 | |
| 141 | + */ | |
| 142 | + } | |
| 143 | + | |
| 144 | + /** | |
| 145 | + * Remove data added by the Abilities API integration (1.8.13). | |
| 146 | + * | |
| 147 | + * Scoped to what THIS feature added, not a blanket log wipe. | |
| 148 | + * | |
| 149 | + * `charitable_abilities_usage` (Charitable_Abilities_Usage::OPTION) is a | |
| 150 | + * dedicated top-level option, never nested inside `charitable_settings`, | |
| 151 | + * so remove_settings() above cannot reach it - it needs its own line. | |
| 152 | + * | |
| 153 | + * Log rows are pruned by TYPE rather than the whole table being | |
| 154 | + * dropped: `charitable_logs` holds every log type Charitable writes, | |
| 155 | + * most of them unrelated to this feature, and remove_tables() above | |
| 156 | + * never drops that table at all (logs are not otherwise touched on | |
| 157 | + * uninstall). Guarded on the table existing, since a site that never | |
| 158 | + * triggered log_create_table() (Charitable_Log_DB::create_table()) has | |
| 159 | + * no table for a bare DELETE to run against. | |
| 160 | + * | |
| 161 | + * @since 1.8.13 | |
| 162 | + * | |
| 163 | + * @global WPDB $wpdb | |
| 164 | + * @return void | |
| 165 | + */ | |
| 166 | + private function remove_abilities_data() { | |
| 167 | + global $wpdb; | |
| 168 | + | |
| 169 | + delete_option( 'charitable_abilities_usage' ); | |
| 170 | + | |
| 171 | + $table = $wpdb->prefix . 'charitable_logs'; | |
| 172 | + | |
| 173 | + if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) === $table ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 174 | + // $table is $wpdb->prefix . 'charitable_logs' and carries no user input; MySQL cannot bind a table identifier as a prepared parameter, so interpolation is the only option. | |
| 175 | + $wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE types = %s", 'abilities' ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter | |
| 126 | 176 | } |
| 127 | 177 | } |
| 128 | 178 | } |
| 129 | 179 | |