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 +49 -22 2.2.0 → 2.11.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
@@ -401,8 +428,11 @@
401 428 'capabilities' => $this->get_user_capabilities(),
402 429 'settings' => $this->get_admin_settings(),
403 430 'i18n' => $this->get_i18n_strings(),
404 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(),
405 435 // One flag per half of the Import / Export page: the "import from
406 436 // another SEO plugin" section, and ThinkRank's own export/restore.
407 437 'migrationToolsEnabled' => (bool) $this->settings->get('enable_migration_tools', false),
408 438 'importExportEnabled' => (bool) $this->settings->get('enable_import_export', false),
@@ -418,8 +448,13 @@
418 448 'faviconUrl' => get_site_icon_url(64) ?: '',
419 449 'adminEmail' => get_option('admin_email'),
420 450 // Post types for Global SEO navigation
421 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(),
422 457 // Role Manager: capabilities the current user holds + the
423 458 // section → capability map, so the SPA can hide sections a role
424 459 // cannot access. Administrators receive every capability.
425 460 'caps' => Capability_Manager::user_capabilities(),
@@ -426,13 +461,10 @@
426 461 'sectionCaps' => Capability_Manager::section_map(),
427 462 'canManageRoles' => Capability_Manager::current_user_can(Capability_Manager::MANAGE_ROLES),
428 463 // Pro detection flag
429 464 '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.
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.
435 467 // MCP (Model Context Protocol) connection details for the MCP page.
436 468 'mcp' => $this->get_mcp_globals(),
437 469 // Google OAuth: JS only ever gets a nonce-signed admin-post URL.
438 470 // The consent URL, client ID, and scopes are assembled by the proxy,
@@ -466,8 +498,13 @@
466 498 }
467 499
468 500 // Check for plugin updates
469 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();
470 507 }
471 508
472 509 /**
473 510 * Load admin page
@@ -779,19 +816,14 @@
779 816 wp_die();
780 817 }
781 818
782 819 /**
783 - * Check if API key is configured
820 + * Check if the selected AI provider is configured
784 821 *
785 - * @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
786 823 */
787 824 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'));
825 + return \ThinkRank\Core\Settings::instance()->has_ai_provider_configured();
794 826 }
795 827
796 828 /**
797 829 * Get menu icon
@@ -854,22 +886,17 @@
854 886 ];
855 887 }
856 888
857 889 /**
858 - * Whether any AI provider API key is configured
890 + * Whether the selected AI provider is configured
859 891 *
860 - * Mirrors the check used by ThinkRank\AI\Manager.
892 + * Same answer as ThinkRank\AI\Manager — both read
893 + * Settings::has_ai_provider_configured().
861 894 *
862 895 * @return bool
863 896 */
864 897 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;
898 + return $this->settings->has_ai_provider_configured();
872 899 }
873 900
874 901 /**
875 902 * Get internationalization strings