PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.10.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.10.0
2.10.0 2.9.0 2.8.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 All 51 releases
← All changes | includes/core/class-activator.php +105 -8 2.4.0 → 2.10.0 View file →
@@ -48,11 +48,13 @@
48 48 delete_option(self::UNINSTALLED_OPTION);
49 49
50 50 $this->check_requirements();
51 51 $this->create_database_tables();
52 - // Must precede set_default_options(): it reads `thinkrank_version`,
53 - // which that method creates.
52 + // Both must precede set_default_options(): they read
53 + // `thinkrank_version`, which that method creates.
54 54 $this->retire_sitemap_legacy_fallback();
55 + $this->seed_feed_defaults();
56 + $this->skip_key_features_migration();
55 57 $this->set_default_options();
56 58 $this->setup_indexnow_key();
57 59 $this->schedule_cron_jobs();
58 60 $this->restore_webroot_artifacts();
@@ -135,15 +137,38 @@
135 137 throw new \Exception(sprintf("Required PHP extension '%s' is not loaded", esc_html($extension)));
136 138 }
137 139 }
138 140
139 - // Check if we can write to WordPress root directory (for robots.txt, llms.txt, sitemaps)
140 - if (!wp_is_writable(ABSPATH)) {
141 - // Log warning but don't block activation — some hosts restrict ABSPATH writes
142 - // and file-writing features will gracefully degrade via WP_Filesystem checks
141 + // Check if we can write to WordPress root directory (for robots.txt, llms.txt,
142 + // the Instant Indexing key file). Never blocks activation — some hosts restrict
143 + // ABSPATH writes by design.
144 + //
145 + // The result is recorded rather than only logged. It used to reach error_log()
146 + // and only under WP_DEBUG, so on a production site nobody was ever told, and the
147 + // features that need it failed later with messages describing the symptom rather
148 + // than the cause (#753). Webroot_Writable_Notice re-evaluates the condition live —
149 + // permissions change without a reactivation — and this value only distinguishes
150 + // "never worked here" from "worked until the host changed something".
151 + $writable = wp_is_writable(ABSPATH);
152 +
153 + update_option(
154 + \ThinkRank\Admin\Webroot_Writable_Notice::OPT_ACTIVATION_STATE,
155 + $writable ? 'writable' : 'not-writable',
156 + false
157 + );
158 +
159 + if (!$writable) {
160 + // A fresh activation on a broken root should warn even if a previous
161 + // install's dismissal is still on record.
162 + delete_option(\ThinkRank\Admin\Webroot_Writable_Notice::OPT_DISMISSED);
163 +
143 164 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
165 + // Not a fixed feature list: robots.txt, llms.txt and the Instant
166 + // Indexing key all have a PHP path, so naming them as broken
167 + // was untrue since #756. Webroot_Writable_Notice works out
168 + // what, if anything, is actually affected.
144 169 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
145 - error_log('ThinkRank: WordPress root directory is not writable. Some features (robots.txt, llms.txt, sitemaps) may not work.');
170 + error_log('ThinkRank: WordPress root directory is not writable. Features on Automatic delivery are served from WordPress; any feature explicitly set to write files cannot publish them.');
146 171 }
147 172 }
148 173 }
149 174
@@ -229,8 +254,80 @@
229 254 add_option(THINKRANK_SITEMAP_MARKED_WRITE_OPTION, '1', '', false);
230 255 }
231 256
232 257 /**
258 + * Give a brand-new install the feed posture the competitors ship with.
259 + *
260 + * The feed controls (#635) default to off in
261 + * {@see Site_Identity_Manager::get_default_settings()}, and they have to:
262 + * two of the three change what a site already publishes. Signing every
263 + * entry adds a line to what existing subscribers receive, and noindexing
264 + * feeds withdraws URLs a site may have had indexed for years — on a podcast
265 + * site, whose feed has to stay indexable, silently at that. Neither belongs
266 + * in a plugin update.
267 + *
268 + * A first install has no subscribers and no indexed feed, so there is
269 + * nothing to change and the protective defaults are simply the right
270 + * starting point — which is what The SEO Framework, Yoast and Rank Math all
271 + * ship. Seeding them here rather than in the defaults is what separates the
272 + * two cases.
273 + *
274 + * Excerpt-only is left off even here: it changes what readers get rather
275 + * than what scrapers can take, and that is the site owner's call.
276 + *
277 + * Same signal and same reasoning as {@see self::retire_sitemap_legacy_fallback()}:
278 + * `thinkrank_version` is absent only on the very first activation, and an
279 + * upgrade does not re-run the activation hook at all.
280 + *
281 + * @since 2.7.0
282 + *
283 + * @return void
284 + */
285 + private function seed_feed_defaults(): void {
286 + if (get_option('thinkrank_version') !== false) {
287 + return;
288 + }
289 +
290 + $manager = new \ThinkRank\SEO\Site_Identity_Manager();
291 +
292 + $manager->save_settings(
293 + 'site',
294 + null,
295 + [
296 + 'feed_source_link' => true,
297 + 'feed_noindex' => true,
298 + ]
299 + );
300 + }
301 +
302 + /**
303 + * Mark the llms.txt Key Features migration done on a fresh install.
304 + *
305 + * {@see \ThinkRank\SEO\LLMs_Txt_Manager::maybe_migrate_legacy_key_features()}
306 + * converts a value saved while commas separated features. A brand-new
307 + * install never saved one, so anything it stores later follows the
308 + * one-per-line rule and must not be split on its commas by a migration
309 + * that runs after the user typed it.
310 + *
311 + * Same signal as {@see self::seed_feed_defaults()}: `thinkrank_version` is
312 + * absent only on the very first activation.
313 + *
314 + * @since 2.10.0
315 + *
316 + * @return void
317 + */
318 + private function skip_key_features_migration(): void {
319 + if (get_option('thinkrank_version') !== false) {
320 + return;
321 + }
322 +
323 + add_option(
324 + \ThinkRank\SEO\LLMs_Txt_Manager::KEY_FEATURES_MIGRATION_OPTION,
325 + \ThinkRank\SEO\LLMs_Txt_Manager::KEY_FEATURES_MIGRATION_VERSION
326 + );
327 + }
328 +
329 + /**
233 330 * Set default plugin options
234 331 *
235 332 * @return void
236 333 */
@@ -239,9 +336,9 @@
239 336 'thinkrank_version' => THINKRANK_VERSION,
240 337
241 338 'thinkrank_ai_provider' => \ThinkRank\Core\Settings::AI_PROVIDER_NONE,
242 339 'thinkrank_cache_duration' => 3600, // 1 hour
243 - 'thinkrank_max_requests_per_minute' => 10,
340 + 'thinkrank_max_requests_per_minute' => 0,
244 341 'thinkrank_enable_logging' => true,
245 342 'thinkrank_auto_optimize' => false,
246 343 'thinkrank_seo_score_threshold' => 70,
247 344 ];