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-settings-manager.php +33 -20 2.0.2 → 2.10.0 View file →
@@ -83,12 +83,21 @@
83 83 'gemini_api_key',
84 84 'gemini_model',
85 85 'openrouter_api_key',
86 86 'openrouter_model',
87 + 'openai_compatible_base_url',
88 + 'openai_compatible_api_key',
89 + 'openai_compatible_model',
90 + 'openai_compatible_timeout',
91 + 'openai_compatible_supports_images',
92 + 'openai_compatible_json_mode',
93 + 'openai_compatible_price_per_million',
87 94 'max_tokens',
88 95 'temperature',
89 96 'cache_duration',
90 97 'max_requests_per_minute',
98 + 'ai_daily_request_limit',
99 + 'ai_paused',
91 100 'enable_logging',
92 101 'debug_mode',
93 102 'api_timeout',
94 103 'retry_attempts',
@@ -257,12 +266,8 @@
257 266 'seo_analytics_google_analytics_property_id',
258 267 'ga_analytics_account_id',
259 268 'ga_analytics_data_stream_id',
260 269
261 - // GA4 Tracking Code Injection (Pro)
262 - 'ga4_auto_inject',
263 - 'ga4_measurement_id',
264 -
265 270 // Search Console configuration
266 271 'search_console_property',
267 272
268 273 // AI features
@@ -649,22 +654,10 @@
649 654 // Prime the option cache in one query before the loop. Every
650 655 // thinkrank_* option is autoload=off, so WordPress cannot serve them
651 656 // from `alloptions` and each Settings->get() below was its own
652 657 // round-trip — 16 of them on every anonymous front-end request, on
653 - // pages that use none of the values. Settings::get() memoizes within a
654 - // request, so only the first read of each key ever hit the database;
655 - // this collapses those first reads into a single query (#393).
656 - //
657 - // wp_prime_option_caches() is WP 6.4+; the plugin supports 6.0, so an
658 - // older site simply keeps the previous behaviour.
659 - if (function_exists('wp_prime_option_caches')) {
660 - wp_prime_option_caches(array_map(
661 - static function (string $key): string {
662 - return 'thinkrank_' . $key;
663 - },
664 - $category_config['keys']
665 - ));
666 - }
658 + // pages that use none of the values (#393).
659 + $this->core_settings->prime($category_config['keys']);
667 660
668 661 $settings = [];
669 662
670 663 foreach ($category_config['keys'] as $key) {
@@ -821,8 +814,10 @@
821 814 switch ($key) {
822 815 case 'openai_api_key':
823 816 case 'claude_api_key':
824 817 case 'openrouter_api_key':
818 + case 'openai_compatible_api_key':
819 + case 'openai_compatible_model':
825 820 if (!empty($value) && !is_string($value)) {
826 821 $validation['valid'] = false;
827 822 $validation['errors'][] = "{$key} must be a string";
828 823 }
@@ -827,15 +822,29 @@
827 822 $validation['errors'][] = "{$key} must be a string";
828 823 }
829 824 break;
830 825
826 + case 'openai_compatible_base_url':
827 + // An unreachable or dangerous URL is refused with a reason
828 + // rather than quietly stored (see Endpoint_URL_Validator).
829 + if (!empty($value)) {
830 + $validated = \ThinkRank\AI\Endpoint_URL_Validator::validate((string) $value);
831 + if (is_wp_error($validated)) {
832 + $validation['valid'] = false;
833 + $validation['errors'][] = $validated->get_error_message();
834 + }
835 + }
836 + break;
837 +
831 838 case 'max_tokens':
832 839 case 'cache_duration':
833 840 case 'max_requests_per_minute':
841 + case 'ai_daily_request_limit':
834 842 case 'seo_score_threshold':
835 843 case 'api_timeout':
836 844 case 'retry_attempts':
837 845 case 'data_retention_days':
846 + case 'openai_compatible_timeout':
838 847 if (!is_numeric($value) || $value < 0) {
839 848 $validation['valid'] = false;
840 849 $validation['errors'][] = "{$key} must be a positive number";
841 850 }
@@ -848,11 +857,15 @@
848 857 }
849 858 break;
850 859
851 860 case 'ai_provider':
852 - if (!in_array($value, ['openai', 'claude', 'gemini', 'openrouter'], true)) {
861 + // '' is legal: it is Settings::AI_PROVIDER_NONE, the state a
862 + // fresh install starts in and the one a user returns to by
863 + // deselecting their provider (#572).
864 + if (!in_array($value, \ThinkRank\Core\Settings::selectable_ai_providers(), true)) {
853 865 $validation['valid'] = false;
854 - $validation['errors'][] = "ai_provider must be 'openai', 'claude', 'gemini', or 'openrouter'";
866 + $validation['errors'][] = "ai_provider must be empty (no provider) or one of: "
867 + . implode(', ', \ThinkRank\Core\Settings::SUPPORTED_AI_PROVIDERS);
855 868 }
856 869 break;
857 870
858 871 case 'dashboard_widgets':