PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.11.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.11.0
2.11.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 All 52 releases
← All changes | includes/admin/class-manager.php +23 -22 2.5.0 → 2.11.0 View file →
@@ -16,8 +16,9 @@
16 16 use ThinkRank\Core\Settings;
17 17 use ThinkRank\Core\Database;
18 18 use ThinkRank\Core\Plan_Config;
19 19 use ThinkRank\Core\Capability_Manager;
20 +use ThinkRank\Config\Local_Business_Types_Config;
20 21 use ThinkRank\Admin\Metabox_Manager;
21 22 use ThinkRank\Admin\Elementor_Metabox;
22 23 use ThinkRank\Admin\Oxygen_Metabox;
23 24 use ThinkRank\Admin\Divi_Metabox;
@@ -427,8 +428,11 @@
427 428 'capabilities' => $this->get_user_capabilities(),
428 429 'settings' => $this->get_admin_settings(),
429 430 'i18n' => $this->get_i18n_strings(),
430 431 'isAdmin' => current_user_can('manage_options'),
432 + // Simple / Advanced navigation for this user (#730). Read once
433 + // when the page is built; the header switch updates it in place.
434 + 'uiMode' => UI_Mode::get(),
431 435 // One flag per half of the Import / Export page: the "import from
432 436 // another SEO plugin" section, and ThinkRank's own export/restore.
433 437 'migrationToolsEnabled' => (bool) $this->settings->get('enable_migration_tools', false),
434 438 'importExportEnabled' => (bool) $this->settings->get('enable_import_export', false),
@@ -444,8 +448,13 @@
444 448 'faviconUrl' => get_site_icon_url(64) ?: '',
445 449 'adminEmail' => get_option('admin_email'),
446 450 // Post types for Global SEO navigation
447 451 'postTypes' => $this->get_public_post_types(),
452 + // schema.org LocalBusiness subtypes for the Local SEO control.
453 + // Localized rather than mirrored in a JS config: the list runs to
454 + // ~150 entries and is also the MCP ability's enum, so a second copy
455 + // would be a second thing to keep in step (#623).
456 + 'localBusinessTypes' => Local_Business_Types_Config::get_options(),
448 457 // Role Manager: capabilities the current user holds + the
449 458 // section → capability map, so the SPA can hide sections a role
450 459 // cannot access. Administrators receive every capability.
451 460 'caps' => Capability_Manager::user_capabilities(),
@@ -452,13 +461,10 @@
452 461 'sectionCaps' => Capability_Manager::section_map(),
453 462 'canManageRoles' => Capability_Manager::current_user_can(Capability_Manager::MANAGE_ROLES),
454 463 // Pro detection flag
455 464 'isPro' => Plan_Config::is_pro(),
456 - // Data update frequency (Pro: daily, Free: every 3 days)
457 - 'dataUpdateFrequency' => Plan_Config::is_pro() ? 'daily' : '3days',
458 - // NB: no per-feature capability maps here. Email Reporting reads
459 - // its capabilities from GET /thinkrank/v1/email-report/config;
460 - // localizing a second copy only invited the two to drift.
465 + // NB: no per-feature capability maps here; each screen reads its
466 + // own state over REST, so a localized copy cannot drift from it.
461 467 // MCP (Model Context Protocol) connection details for the MCP page.
462 468 'mcp' => $this->get_mcp_globals(),
463 469 // Google OAuth: JS only ever gets a nonce-signed admin-post URL.
464 470 // The consent URL, client ID, and scopes are assembled by the proxy,
@@ -492,8 +498,13 @@
492 498 }
493 499
494 500 // Check for plugin updates
495 501 $this->check_plugin_updates();
502 +
503 + // One-time: a Key Features value saved while commas were delimiters
504 + // becomes one feature per line, so the next regeneration publishes the
505 + // bullets the site already had rather than one merged line.
506 + \ThinkRank\SEO\LLMs_Txt_Manager::maybe_migrate_legacy_key_features();
496 507 }
497 508
498 509 /**
499 510 * Load admin page
@@ -805,19 +816,14 @@
805 816 wp_die();
806 817 }
807 818
808 819 /**
809 - * Check if API key is configured
820 + * Check if the selected AI provider is configured
810 821 *
811 - * @return bool True if at least one API key is configured
822 + * @return bool True when the chosen provider has what it needs to run
812 823 */
813 824 private function has_api_key_configured(): bool {
814 - $settings = \ThinkRank\Core\Settings::instance();
815 -
816 - return !empty($settings->get('openai_api_key'))
817 - || !empty($settings->get('claude_api_key'))
818 - || !empty($settings->get('gemini_api_key'))
819 - || !empty($settings->get('openrouter_api_key'));
825 + return \ThinkRank\Core\Settings::instance()->has_ai_provider_configured();
820 826 }
821 827
822 828 /**
823 829 * Get menu icon
@@ -880,22 +886,17 @@
880 886 ];
881 887 }
882 888
883 889 /**
884 - * Whether any AI provider API key is configured
890 + * Whether the selected AI provider is configured
885 891 *
886 - * Mirrors the check used by ThinkRank\AI\Manager.
892 + * Same answer as ThinkRank\AI\Manager — both read
893 + * Settings::has_ai_provider_configured().
887 894 *
888 895 * @return bool
889 896 */
890 897 private function is_ai_configured(): bool {
891 - foreach (['openai_api_key', 'claude_api_key', 'gemini_api_key', 'openrouter_api_key'] as $key) {
892 - if (!empty($this->settings->get($key, ''))) {
893 - return true;
894 - }
895 - }
896 -
897 - return false;
898 + return $this->settings->has_ai_provider_configured();
898 899 }
899 900
900 901 /**
901 902 * Get internationalization strings