PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.9.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.9.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 1.0.2 All 50 releases
← All changes | includes/core/class-activator.php +73 -8 2.2.02.9.0 View file →
@@ -48,11 +48,12 @@
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();
55 56 $this->set_default_options();
56 57 $this->setup_indexnow_key();
57 58 $this->schedule_cron_jobs();
58 59 $this->restore_webroot_artifacts();
@@ -135,15 +136,34 @@
135 136 throw new \Exception(sprintf("Required PHP extension '%s' is not loaded", esc_html($extension)));
136 137 }
137 138 }
138 139
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
140 + // Check if we can write to WordPress root directory (for robots.txt, llms.txt,
141 + // the Instant Indexing key file). Never blocks activation — some hosts restrict
142 + // ABSPATH writes by design.
143 + //
144 + // The result is recorded rather than only logged. It used to reach error_log()
145 + // and only under WP_DEBUG, so on a production site nobody was ever told, and the
146 + // features that need it failed later with messages describing the symptom rather
147 + // than the cause (#753). Webroot_Writable_Notice re-evaluates the condition live —
148 + // permissions change without a reactivation — and this value only distinguishes
149 + // "never worked here" from "worked until the host changed something".
150 + $writable = wp_is_writable(ABSPATH);
151 +
152 + update_option(
153 + \ThinkRank\Admin\Webroot_Writable_Notice::OPT_ACTIVATION_STATE,
154 + $writable ? 'writable' : 'not-writable',
155 + false
156 + );
157 +
158 + if (!$writable) {
159 + // A fresh activation on a broken root should warn even if a previous
160 + // install's dismissal is still on record.
161 + delete_option(\ThinkRank\Admin\Webroot_Writable_Notice::OPT_DISMISSED);
162 +
143 163 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
144 164 // 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.');
165 + error_log('ThinkRank: WordPress root directory is not writable. robots.txt, llms.txt and the Instant Indexing key file cannot be published; the sitemap falls back to dynamic delivery.');
146 166 }
147 167 }
148 168 }
149 169
@@ -229,8 +249,53 @@
229 249 add_option(THINKRANK_SITEMAP_MARKED_WRITE_OPTION, '1', '', false);
230 250 }
231 251
232 252 /**
253 + * Give a brand-new install the feed posture the competitors ship with.
254 + *
255 + * The feed controls (#635) default to off in
256 + * {@see Site_Identity_Manager::get_default_settings()}, and they have to:
257 + * two of the three change what a site already publishes. Signing every
258 + * entry adds a line to what existing subscribers receive, and noindexing
259 + * feeds withdraws URLs a site may have had indexed for years — on a podcast
260 + * site, whose feed has to stay indexable, silently at that. Neither belongs
261 + * in a plugin update.
262 + *
263 + * A first install has no subscribers and no indexed feed, so there is
264 + * nothing to change and the protective defaults are simply the right
265 + * starting point — which is what The SEO Framework, Yoast and Rank Math all
266 + * ship. Seeding them here rather than in the defaults is what separates the
267 + * two cases.
268 + *
269 + * Excerpt-only is left off even here: it changes what readers get rather
270 + * than what scrapers can take, and that is the site owner's call.
271 + *
272 + * Same signal and same reasoning as {@see self::retire_sitemap_legacy_fallback()}:
273 + * `thinkrank_version` is absent only on the very first activation, and an
274 + * upgrade does not re-run the activation hook at all.
275 + *
276 + * @since 2.7.0
277 + *
278 + * @return void
279 + */
280 + private function seed_feed_defaults(): void {
281 + if (get_option('thinkrank_version') !== false) {
282 + return;
283 + }
284 +
285 + $manager = new \ThinkRank\SEO\Site_Identity_Manager();
286 +
287 + $manager->save_settings(
288 + 'site',
289 + null,
290 + [
291 + 'feed_source_link' => true,
292 + 'feed_noindex' => true,
293 + ]
294 + );
295 + }
296 +
297 + /**
233 298 * Set default plugin options
234 299 *
235 300 * @return void
236 301 */
@@ -239,9 +304,9 @@
239 304 'thinkrank_version' => THINKRANK_VERSION,
240 305
241 306 'thinkrank_ai_provider' => \ThinkRank\Core\Settings::AI_PROVIDER_NONE,
242 307 'thinkrank_cache_duration' => 3600, // 1 hour
243 - 'thinkrank_max_requests_per_minute' => 10,
308 + 'thinkrank_max_requests_per_minute' => 0,
244 309 'thinkrank_enable_logging' => true,
245 310 'thinkrank_auto_optimize' => false,
246 311 'thinkrank_seo_score_threshold' => 70,
247 312 ];