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/admin/class-manager.php +46 -22 2.2.0 → 2.10.0 View file →
@@ -16,12 +16,15 @@
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;
25 +use ThinkRank\Admin\Bricks_Metabox;
26 +use ThinkRank\Admin\Beaver_Metabox;
24 27 use ThinkRank\Admin\Bulk_Action_Manager;
25 28 use ThinkRank\Admin\Post_List_Filters;
26 29
27 30 // Prevent direct access
@@ -80,8 +83,22 @@
80 83 */
81 84 private Divi_Metabox $divi_metabox;
82 85
83 86 /**
87 + * Bricks builder metabox integration instance
88 + *
89 + * @var Bricks_Metabox
90 + */
91 + private Bricks_Metabox $bricks_metabox;
92 +
93 + /**
94 + * Beaver Builder metabox integration
95 + *
96 + * @var Beaver_Metabox
97 + */
98 + private Beaver_Metabox $beaver_metabox;
99 +
100 + /**
84 101 * Post list columns instance
85 102 *
86 103 * @var Post_List_Columns
87 104 */
@@ -134,8 +151,10 @@
134 151 $this->metabox_manager = new Metabox_Manager($this->settings);
135 152 $this->elementor_metabox = new Elementor_Metabox($this->metabox_manager);
136 153 $this->oxygen_metabox = new Oxygen_Metabox($this->metabox_manager);
137 154 $this->divi_metabox = new Divi_Metabox($this->metabox_manager);
155 + $this->bricks_metabox = new Bricks_Metabox($this->metabox_manager);
156 + $this->beaver_metabox = new Beaver_Metabox($this->metabox_manager);
138 157 $this->post_list_columns = new Post_List_Columns();
139 158 $this->focus_keyword_ajax = new Focus_Keyword_Ajax();
140 159 $this->seo_quick_edit_ajax = new Seo_Quick_Edit_Ajax();
141 160 $this->bulk_action_manager = new Bulk_Action_Manager();
@@ -171,8 +190,16 @@
171 190 // Initialize Divi Visual Builder integration (hooks gate on the VB
172 191 // request, so they no-op without Divi)
173 192 $this->divi_metabox->init();
174 193
194 + // Initialize Bricks builder integration (hooks gate on Bricks' own
195 + // builder detector, so they no-op without Bricks)
196 + $this->bricks_metabox->init();
197 +
198 + // Initialize Beaver Builder integration (hooks gate on Beaver Builder's
199 + // own builder detector, so they no-op without Beaver Builder)
200 + $this->beaver_metabox->init();
201 +
175 202 // Initialize post list columns
176 203 $this->post_list_columns->init();
177 204
178 205 // Initialize focus keyword AJAX handler
@@ -418,8 +445,13 @@
418 445 'faviconUrl' => get_site_icon_url(64) ?: '',
419 446 'adminEmail' => get_option('admin_email'),
420 447 // Post types for Global SEO navigation
421 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(),
422 454 // Role Manager: capabilities the current user holds + the
423 455 // section → capability map, so the SPA can hide sections a role
424 456 // cannot access. Administrators receive every capability.
425 457 'caps' => Capability_Manager::user_capabilities(),
@@ -426,13 +458,10 @@
426 458 'sectionCaps' => Capability_Manager::section_map(),
427 459 'canManageRoles' => Capability_Manager::current_user_can(Capability_Manager::MANAGE_ROLES),
428 460 // Pro detection flag
429 461 'isPro' => Plan_Config::is_pro(),
430 - // Data update frequency (Pro: daily, Free: every 3 days)
431 - 'dataUpdateFrequency' => Plan_Config::is_pro() ? 'daily' : '3days',
432 - // NB: no per-feature capability maps here. Email Reporting reads
433 - // its capabilities from GET /thinkrank/v1/email-report/config;
434 - // localizing a second copy only invited the two to drift.
462 + // NB: no per-feature capability maps here; each screen reads its
463 + // own state over REST, so a localized copy cannot drift from it.
435 464 // MCP (Model Context Protocol) connection details for the MCP page.
436 465 'mcp' => $this->get_mcp_globals(),
437 466 // Google OAuth: JS only ever gets a nonce-signed admin-post URL.
438 467 // The consent URL, client ID, and scopes are assembled by the proxy,
@@ -466,8 +495,13 @@
466 495 }
467 496
468 497 // Check for plugin updates
469 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();
470 504 }
471 505
472 506 /**
473 507 * Load admin page
@@ -779,19 +813,14 @@
779 813 wp_die();
780 814 }
781 815
782 816 /**
783 - * Check if API key is configured
817 + * Check if the selected AI provider is configured
784 818 *
785 - * @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
786 820 */
787 821 private function has_api_key_configured(): bool {
788 - $settings = \ThinkRank\Core\Settings::instance();
789 -
790 - return !empty($settings->get('openai_api_key'))
791 - || !empty($settings->get('claude_api_key'))
792 - || !empty($settings->get('gemini_api_key'))
793 - || !empty($settings->get('openrouter_api_key'));
822 + return \ThinkRank\Core\Settings::instance()->has_ai_provider_configured();
794 823 }
795 824
796 825 /**
797 826 * Get menu icon
@@ -854,22 +883,17 @@
854 883 ];
855 884 }
856 885
857 886 /**
858 - * Whether any AI provider API key is configured
887 + * Whether the selected AI provider is configured
859 888 *
860 - * Mirrors the check used by ThinkRank\AI\Manager.
889 + * Same answer as ThinkRank\AI\Manager — both read
890 + * Settings::has_ai_provider_configured().
861 891 *
862 892 * @return bool
863 893 */
864 894 private function is_ai_configured(): bool {
865 - foreach (['openai_api_key', 'claude_api_key', 'gemini_api_key', 'openrouter_api_key'] as $key) {
866 - if (!empty($this->settings->get($key, ''))) {
867 - return true;
868 - }
869 - }
870 -
871 - return false;
895 + return $this->settings->has_ai_provider_configured();
872 896 }
873 897
874 898 /**
875 899 * Get internationalization strings