PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.7.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.7.0
2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
← All changes | uninstall.php +51 -1 2.0.22.7.0 View file →
@@ -69,8 +69,26 @@
69 69 // Settings class default and the documented UI behavior — only nuke data when
70 70 // the user has explicitly enabled "Delete all data on uninstall".
71 71 $keep_data = (bool) get_option('thinkrank_keep_data_on_uninstall', true);
72 72
73 + // Files first, and regardless of $keep_data.
74 + //
75 + // Ordering: every ownership test in there reads state the database
76 + // cleanup below is about to destroy — sitemap filenames come from the
77 + // settings table, the IndexNow key file's name from an option. Run it
78 + // after, and there is nothing left to identify our files by.
79 + //
80 + // Not gated on $keep_data because these are not the user's data. They
81 + // are artifacts of a plugin that is being removed, and leaving them is
82 + // actively harmful: a real file at /sitemap_index.xml is served by the
83 + // web server before WordPress boots, so it goes on shadowing RankMath,
84 + // Squirrly or core's own sitemap indefinitely — while rendering blank,
85 + // since the XSL stylesheet it points at leaves with the plugin (#510).
86 + // "Keep my data" means keep the settings for a reinstall, not keep a
87 + // dead file breaking the next plugin. On reinstall they are republished
88 + // from the settings that were kept.
89 + self::remove_webroot_files();
90 +
73 91 if (!$keep_data) {
74 92 self::remove_database_tables();
75 93 self::remove_options();
76 94 self::remove_user_meta();
@@ -84,8 +102,38 @@
84 102 self::mark_uninstalled();
85 103 }
86 104
87 105 /**
106 + * Delete every file ThinkRank published into the WordPress web root.
107 + *
108 + * The sitemap, robots.txt, llms.txt and the IndexNow key file are real files
109 + * in `ABSPATH`, not routes, so removing the plugin has to remove them too —
110 + * otherwise the web server keeps serving a sitemap belonging to a plugin
111 + * that is no longer installed, and the next SEO plugin's own sitemap can
112 + * never answer (#510).
113 + *
114 + * @since 2.1.0
115 + *
116 + * @return void
117 + */
118 + private static function remove_webroot_files(): void {
119 + // No autoloader here — WP_UNINSTALL_PLUGIN loads this file without the
120 + // plugin — so the removal logic comes from the same plain function file
121 + // the deactivator and the sitemap generator use. One copy, not three.
122 + $shared = __DIR__ . '/includes/cleanup-webroot.php';
123 +
124 + if (!is_readable($shared)) {
125 + return;
126 + }
127 +
128 + require_once $shared;
129 +
130 + if (function_exists('thinkrank_webroot_cleanup')) {
131 + thinkrank_webroot_cleanup();
132 + }
133 + }
134 +
135 + /**
88 136 * The shared cleanup manifest.
89 137 *
90 138 * There is no autoloader here — WP_UNINSTALL_PLUGIN loads this file without
91 139 * the plugin — so the cron-hook and capability lists come from a plain
@@ -141,9 +189,11 @@
141 189 $wpdb->prefix . 'thinkrank_seo_local',
142 190 $wpdb->prefix . 'thinkrank_email_report_logs',
143 191 // AI Visibility Tables. These were registered in Database_Schema but
144 192 // never listed here, so an uninstall left them behind — bv_tasks in
145 - // particular holds the full text of every AI answer (#302).
193 + // particular holds the full text of every AI answer (#302). The
194 + // three Brand Visibility tables are no longer created, but sites
195 + // that used the feature before it was removed still have them.
146 196 $wpdb->prefix . 'thinkrank_ai_traffic',
147 197 $wpdb->prefix . 'thinkrank_brand_visibility_checks',
148 198 $wpdb->prefix . 'thinkrank_bv_runs',
149 199 $wpdb->prefix . 'thinkrank_bv_tasks',