| @@ -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; |
| @@ -444,8 +445,13 @@ | ||
| 444 | 445 | 'faviconUrl' => get_site_icon_url(64) ?: '', |
| 445 | 446 | 'adminEmail' => get_option('admin_email'), |
| 446 | 447 | // Post types for Global SEO navigation |
| 447 | 448 | 'postTypes' => $this->get_public_post_types(), |
| 449 | + // schema.org LocalBusiness subtypes for the Local SEO control. | |
| 450 | + // Localized rather than mirrored in a JS config: the list runs to | |
| 451 | + // ~150 entries and is also the MCP ability's enum, so a second copy | |
| 452 | + // would be a second thing to keep in step (#623). | |
| 453 | + 'localBusinessTypes' => Local_Business_Types_Config::get_options(), | |
| 448 | 454 | // Role Manager: capabilities the current user holds + the |
| 449 | 455 | // section → capability map, so the SPA can hide sections a role |
| 450 | 456 | // cannot access. Administrators receive every capability. |
| 451 | 457 | 'caps' => Capability_Manager::user_capabilities(), |
| @@ -489,8 +495,13 @@ | ||
| 489 | 495 | } |
| 490 | 496 | |
| 491 | 497 | // Check for plugin updates |
| 492 | 498 | $this->check_plugin_updates(); |
| 499 | + | |
| 500 | + // One-time: a Key Features value saved while commas were delimiters | |
| 501 | + // becomes one feature per line, so the next regeneration publishes the | |
| 502 | + // bullets the site already had rather than one merged line. | |
| 503 | + \ThinkRank\SEO\LLMs_Txt_Manager::maybe_migrate_legacy_key_features(); | |
| 493 | 504 | } |
| 494 | 505 | |
| 495 | 506 | /** |
| 496 | 507 | * Load admin page |
| @@ -802,19 +813,14 @@ | ||
| 802 | 813 | wp_die(); |
| 803 | 814 | } |
| 804 | 815 | |
| 805 | 816 | /** |
| 806 | - * Check if API key is configured | |
| 817 | + * Check if the selected AI provider is configured | |
| 807 | 818 | * |
| 808 | - * @return bool True if at least one API key is configured | |
| 819 | + * @return bool True when the chosen provider has what it needs to run | |
| 809 | 820 | */ |
| 810 | 821 | private function has_api_key_configured(): bool { |
| 811 | - $settings = \ThinkRank\Core\Settings::instance(); | |
| 812 | - | |
| 813 | - return !empty($settings->get('openai_api_key')) | |
| 814 | - || !empty($settings->get('claude_api_key')) | |
| 815 | - || !empty($settings->get('gemini_api_key')) | |
| 816 | - || !empty($settings->get('openrouter_api_key')); | |
| 822 | + return \ThinkRank\Core\Settings::instance()->has_ai_provider_configured(); | |
| 817 | 823 | } |
| 818 | 824 | |
| 819 | 825 | /** |
| 820 | 826 | * Get menu icon |
| @@ -877,22 +883,17 @@ | ||
| 877 | 883 | ]; |
| 878 | 884 | } |
| 879 | 885 | |
| 880 | 886 | /** |
| 881 | - * Whether any AI provider API key is configured | |
| 887 | + * Whether the selected AI provider is configured | |
| 882 | 888 | * |
| 883 | - * Mirrors the check used by ThinkRank\AI\Manager. | |
| 889 | + * Same answer as ThinkRank\AI\Manager — both read | |
| 890 | + * Settings::has_ai_provider_configured(). | |
| 884 | 891 | * |
| 885 | 892 | * @return bool |
| 886 | 893 | */ |
| 887 | 894 | private function is_ai_configured(): bool { |
| 888 | - foreach (['openai_api_key', 'claude_api_key', 'gemini_api_key', 'openrouter_api_key'] as $key) { | |
| 889 | - if (!empty($this->settings->get($key, ''))) { | |
| 890 | - return true; | |
| 891 | - } | |
| 892 | - } | |
| 893 | - | |
| 894 | - return false; | |
| 895 | + return $this->settings->has_ai_provider_configured(); | |
| 895 | 896 | } |
| 896 | 897 | |
| 897 | 898 | /** |
| 898 | 899 | * Get internationalization strings |