PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / trunk
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO vtrunk
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 1.0.2 1.1.0 1.10.0 1.11.0 All 47 releases
thinkrank / includes / admin / class-dashboard-widget.php

class-dashboard-widget.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO trunk, at includes/admin/class-dashboard-widget.php

168 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * WordPress Dashboard Widget
5 *
6 * Registers the "ThinkRank Website Insights" widget on the wp-admin Dashboard
7 * (index.php). Before a Google account is connected it shows an empty state
8 * with a "Connect to Google Search Console" call to action; once connected it
9 * renders live Search Console performance metrics.
10 *
11 * The widget is a small standalone React island (the `dashboard-widget` webpack
12 * entry) mounted into `#thinkrank-dashboard-widget`. It talks to the existing
13 * `/thinkrank/v1/seo-analytics/*` REST routes and reuses the shared Google
14 * OAuth proxy connect URL — no Google credentials ever touch the browser.
15 *
16 * @package ThinkRank\Admin
17 * @since 1.0.0
18 */
19
20 declare(strict_types=1);
21
22 namespace ThinkRank\Admin;
23
24 use ThinkRank\Core\Settings;
25 use ThinkRank\Core\Plan_Config;
26 use ThinkRank\Integrations\Google_OAuth_Proxy;
27
28 // Prevent direct access.
29 if (!defined('ABSPATH')) {
30 exit;
31 }
32
33 /**
34 * Dashboard Widget controller.
35 *
36 * Single Responsibility: register and render the ThinkRank dashboard widget.
37 *
38 * @since 1.0.0
39 */
40 class Dashboard_Widget {
41
42 /**
43 * Widget DOM/registration id.
44 *
45 * @var string
46 */
47 private const WIDGET_ID = 'thinkrank_website_insights';
48
49 /**
50 * Capability required to see the widget.
51 *
52 * Connecting a Google account requires `manage_options` (see
53 * Google_OAuth_Proxy::handle_connect), so gate the whole widget on the
54 * same capability rather than showing a connect button that would 403.
55 *
56 * @var string
57 */
58 private const CAPABILITY = 'manage_options';
59
60 /**
61 * Register WordPress hooks.
62 *
63 * @return void
64 */
65 public function init(): void {
66 add_action('wp_dashboard_setup', [$this, 'register_widget']);
67 add_action('admin_enqueue_scripts', [$this, 'enqueue_assets']);
68 }
69
70 /**
71 * Register the dashboard widget.
72 *
73 * @return void
74 */
75 public function register_widget(): void {
76 if (!current_user_can(self::CAPABILITY)) {
77 return;
78 }
79
80 wp_add_dashboard_widget(
81 self::WIDGET_ID,
82 __('ThinkRank Website Insights', 'thinkrank'),
83 [$this, 'render']
84 );
85 }
86
87 /**
88 * Render the widget container.
89 *
90 * The React app mounts here; the fallback text only shows if the bundle
91 * fails to load or JavaScript is disabled.
92 *
93 * @return void
94 */
95 public function render(): void {
96 echo '<div id="thinkrank-dashboard-widget" class="thinkrank-dashboard-widget">';
97 echo '<p class="thinkrank-dashboard-widget__fallback">'
98 . esc_html__('Loading ThinkRank insights…', 'thinkrank')
99 . '</p>';
100 echo '</div>';
101 }
102
103 /**
104 * Enqueue the widget bundle on the Dashboard screen only.
105 *
106 * @param string $hook_suffix Current admin page hook.
107 * @return void
108 */
109 public function enqueue_assets(string $hook_suffix): void {
110 // Core Dashboard screen only, and only for users who can see the widget.
111 if ($hook_suffix !== 'index.php' || !current_user_can(self::CAPABILITY)) {
112 return;
113 }
114
115 $asset_file = THINKRANK_PLUGIN_DIR . 'assets/dashboard-widget.asset.php';
116 $asset = file_exists($asset_file) ? include $asset_file : [
117 'dependencies' => ['wp-element', 'wp-components', 'wp-api-fetch', 'wp-i18n'],
118 'version' => THINKRANK_VERSION,
119 ];
120
121 wp_enqueue_script(
122 'thinkrank-dashboard-widget',
123 THINKRANK_PLUGIN_URL . 'assets/dashboard-widget.js',
124 $asset['dependencies'],
125 $asset['version'],
126 true
127 );
128
129 wp_enqueue_style(
130 'thinkrank-dashboard-widget',
131 THINKRANK_PLUGIN_URL . 'assets/dashboard-widget.css',
132 ['wp-components'],
133 $asset['version']
134 );
135
136 $settings = Settings::instance();
137
138 wp_localize_script('thinkrank-dashboard-widget', 'thinkrankDashboardWidget', [
139 'apiUrl' => rest_url('thinkrank/v1/'),
140 'restNonce' => wp_create_nonce('wp_rest'),
141 'connected' => (bool) $settings->get('google_account_connected', false),
142 'isPro' => Plan_Config::is_pro(),
143 // is_pro() is licence-aware, so it is false on an activated-but-
144 // unlicensed install and the bar upsold Pro to someone who already
145 // had it. The widget needs the installed-state separately.
146 'isProInstalled' => defined('THINKRANK_PRO_VERSION'),
147 'licenseUrl' => admin_url('admin.php?page=thinkrank-license'),
148 // Pro upsell target for the teaser bar (filterable so campaigns can
149 // point it at a specific landing page).
150 'upgradeUrl' => apply_filters(
151 'thinkrank_dashboard_widget_upgrade_url',
152 'https://thinkrank.ai/#pricing'
153 ),
154 // The "Connect to Google Search Console" button starts the OAuth
155 // flow directly. JS only ever gets a nonce-signed admin-post URL —
156 // the consent URL, client id, and scopes are assembled by the proxy,
157 // never in the browser. The flow returns to the Dashboard when done.
158 'connectUrl' => Google_OAuth_Proxy::get_connect_url(admin_url('index.php')),
159 // "View More" (connected state) deep-links to Analytics › Dashboard
160 // inside the Essential SEO SPA (nav_section/nav_item drive the tab).
161 'settingsUrl' => admin_url('admin.php?page=thinkrank-essential-seo&nav_section=analytics&nav_item=dashboard'),
162 // Where the Search Console property is picked — the fix for the most
163 // common widget error (connected account, no property selected).
164 'propertyUrl' => admin_url('admin.php?page=thinkrank-essential-seo&nav_section=integrations&nav_item=google-services'),
165 ]);
166 }
167 }
168