PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.9.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.9.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/api/class-ai-insights-endpoint.php +7 -231 1.28.0 → 2.9.0 View file →
@@ -1,17 +1,17 @@
1 1 <?php
2 2 /**
3 3 * AI Insights API endpoints.
4 4 *
5 - * Admin REST surface for the AI Insights screen (#248 P1 trio):
5 + * Admin REST surface for the AI Insights screen (#248 P1):
6 6 *
7 7 * GET /ai-insights/traffic — AI referral/crawler dashboard summary
8 - * GET /ai-insights/brand — saved queries + check history
9 - * POST /ai-insights/brand — save the query list
10 - * POST /ai-insights/brand/run — run checks now (paid AI calls, capped)
11 - * GET /ai-insights/auto-ai — auto-optimization settings + last run
12 - * POST /ai-insights/auto-ai — save auto-optimization settings
13 8 *
9 + * Automatic AI metadata on publish, the other tab on this screen, is a
10 + * ThinkRank Pro feature and registers its own routes there (#673). Brand
11 + * Visibility used to live in this section too; its v1 routes here were removed
12 + * in 1.30.0 (#301), and the feature itself was removed later.
13 + *
14 14 * @package ThinkRank
15 15 * @subpackage API
16 16 * @since 1.27.0
17 17 */
@@ -19,12 +19,9 @@
19 19 declare(strict_types=1);
20 20
21 21 namespace ThinkRank\API;
22 22
23 -use ThinkRank\AI\Brand_Visibility_Checker;
24 -use ThinkRank\Core\Settings;
25 23 use ThinkRank\SEO\Ai_Traffic_Tracker;
26 -use ThinkRank\SEO\Auto_Ai_Optimizer;
27 24 use WP_REST_Controller;
28 25 use WP_REST_Request;
29 26 use WP_REST_Response;
30 27
@@ -33,9 +30,9 @@
33 30 exit;
34 31 }
35 32
36 33 /**
37 - * REST controller for AI traffic, brand visibility, and auto AI settings.
34 + * REST controller for AI traffic.
38 35 */
39 36 class Ai_Insights_Endpoint extends WP_REST_Controller {
40 37
41 38 /**
@@ -71,93 +68,8 @@
71 68 'maximum' => 180,
72 69 ],
73 70 ],
74 71 ]);
75 -
76 - register_rest_route($this->namespace, '/' . $this->rest_base . '/brand', [
77 - [
78 - 'methods' => 'GET',
79 - 'callback' => [$this, 'get_brand'],
80 - 'permission_callback' => [$this, 'check_admin_permissions'],
81 - ],
82 - [
83 - 'methods' => 'POST',
84 - 'callback' => [$this, 'save_brand_queries'],
85 - 'permission_callback' => [$this, 'check_admin_permissions'],
86 - 'args' => [
87 - 'queries' => [
88 - 'required' => true,
89 - 'type' => 'array',
90 - 'items' => ['type' => 'string'],
91 - 'sanitize_callback' => static function ($value) {
92 - if (!is_array($value)) {
93 - return [];
94 - }
95 - $clean = array_values(array_filter(array_map(
96 - static fn($q) => sanitize_text_field((string) $q),
97 - $value
98 - )));
99 - // Clamp to the plan's cap, not the hard ceiling, so
100 - // free can't persist queries it may not run.
101 - return array_slice($clean, 0, Brand_Visibility_Checker::query_limit());
102 - },
103 - ],
104 - ],
105 - ],
106 - ]);
107 -
108 - register_rest_route($this->namespace, '/' . $this->rest_base . '/brand/run', [
109 - 'methods' => 'POST',
110 - 'callback' => [$this, 'run_brand_checks'],
111 - 'permission_callback' => [$this, 'check_admin_permissions'],
112 - ]);
113 -
114 - register_rest_route($this->namespace, '/' . $this->rest_base . '/brand/history/(?P<id>\d+)', [
115 - 'methods' => 'DELETE',
116 - 'callback' => [$this, 'delete_brand_history'],
117 - 'permission_callback' => [$this, 'check_admin_permissions'],
118 - 'args' => [
119 - 'id' => [
120 - 'required' => true,
121 - 'type' => 'integer',
122 - 'minimum' => 1,
123 - ],
124 - ],
125 - ]);
126 -
127 - register_rest_route($this->namespace, '/' . $this->rest_base . '/auto-ai', [
128 - [
129 - 'methods' => 'GET',
130 - 'callback' => [$this, 'get_auto_ai'],
131 - 'permission_callback' => [$this, 'check_admin_permissions'],
132 - ],
133 - [
134 - 'methods' => 'POST',
135 - 'callback' => [$this, 'save_auto_ai'],
136 - 'permission_callback' => [$this, 'check_admin_permissions'],
137 - 'args' => [
138 - 'enabled' => [
139 - 'required' => false,
140 - 'type' => 'boolean',
141 - ],
142 - 'post_types' => [
143 - 'required' => false,
144 - 'type' => 'array',
145 - 'items' => ['type' => 'string'],
146 - 'sanitize_callback' => static function ($value) {
147 - if (!is_array($value)) {
148 - return [];
149 - }
150 - // Only real, public post types survive.
151 - return array_values(array_filter(
152 - array_map('sanitize_key', $value),
153 - static fn($t) => post_type_exists($t)
154 - ));
155 - },
156 - ],
157 - ],
158 - ],
159 - ]);
160 72 }
161 73
162 74 /**
163 75 * Admin permission gate (matches the other admin-only endpoints).
@@ -180,142 +92,6 @@
180 92 return new WP_REST_Response([
181 93 'success' => true,
182 94 'data' => $tracker->summary((int) $request->get_param('days')),
183 95 ], 200);
184 - }
185 -
186 - /**
187 - * Saved brand queries + history.
188 - *
189 - * @return WP_REST_Response
190 - */
191 - public function get_brand(): WP_REST_Response {
192 - $checker = new Brand_Visibility_Checker();
193 -
194 - return new WP_REST_Response([
195 - 'success' => true,
196 - 'data' => [
197 - 'queries' => $checker->queries(),
198 - 'history' => $checker->history(),
199 - // The plan's cap, not the hard ceiling — the UI renders the
200 - // limit the user can actually use.
201 - 'max_queries' => Brand_Visibility_Checker::query_limit(),
202 - 'plan' => \ThinkRank\Core\Plan_Config::ai_visibility(),
203 - 'is_pro' => \ThinkRank\Core\Plan_Config::is_pro(),
204 - 'brand' => (string) get_bloginfo('name'),
205 - 'host' => (string) wp_parse_url(home_url(), PHP_URL_HOST),
206 - ],
207 - ], 200);
208 - }
209 -
210 - /**
211 - * Save the brand query list.
212 - *
213 - * @param WP_REST_Request $request Request.
214 - * @return WP_REST_Response
215 - */
216 - public function save_brand_queries(WP_REST_Request $request): WP_REST_Response {
217 - $queries = (array) $request->get_param('queries');
218 - Settings::instance()->set('brand_visibility_queries', $queries);
219 -
220 - return new WP_REST_Response([
221 - 'success' => true,
222 - 'data' => ['queries' => $queries],
223 - ], 200);
224 - }
225 -
226 - /**
227 - * Run brand checks now.
228 - *
229 - * @return WP_REST_Response
230 - */
231 - public function run_brand_checks(): WP_REST_Response {
232 - try {
233 - $checker = new Brand_Visibility_Checker();
234 - $results = $checker->run();
235 - } catch (\Exception $e) {
236 - return new WP_REST_Response([
237 - 'success' => false,
238 - 'message' => $e->getMessage(),
239 - ], 400);
240 - }
241 -
242 - return new WP_REST_Response([
243 - 'success' => true,
244 - 'data' => [
245 - 'results' => $results,
246 - 'history' => (new Brand_Visibility_Checker())->history(),
247 - ],
248 - ], 200);
249 - }
250 -
251 - /**
252 - * Delete a single brand check-history row.
253 - *
254 - * @param WP_REST_Request $request Request.
255 - * @return WP_REST_Response
256 - */
257 - public function delete_brand_history(WP_REST_Request $request): WP_REST_Response {
258 - $id = (int) $request->get_param('id');
259 - $checker = new Brand_Visibility_Checker();
260 - $deleted = $checker->delete_history($id);
261 -
262 - return new WP_REST_Response([
263 - 'success' => $deleted,
264 - 'data' => [
265 - 'id' => $id,
266 - 'history' => $checker->history(),
267 - ],
268 - ], $deleted ? 200 : 404);
269 - }
270 -
271 - /**
272 - * Auto AI settings + last run outcome.
273 - *
274 - * @return WP_REST_Response
275 - */
276 - public function get_auto_ai(): WP_REST_Response {
277 - $settings = Settings::instance();
278 -
279 - return new WP_REST_Response([
280 - 'success' => true,
281 - 'data' => [
282 - 'enabled' => (bool) $settings->get('auto_ai_meta_enabled', false),
283 - 'post_types' => (array) $settings->get('auto_ai_meta_post_types', ['post']),
284 - 'last_run' => get_option(Auto_Ai_Optimizer::LAST_RUN_OPTION, null),
285 - // Pro-gated: the UI locks the toggle and shows the upsell.
286 - 'available' => \ThinkRank\Core\Plan_Config::can('auto_ai_meta', 'ai_visibility'),
287 - ],
288 - ], 200);
289 - }
290 -
291 - /**
292 - * Save auto AI settings.
293 - *
294 - * @param WP_REST_Request $request Request.
295 - * @return WP_REST_Response
296 - */
297 - public function save_auto_ai(WP_REST_Request $request): WP_REST_Response {
298 - $settings = Settings::instance();
299 -
300 - if (null !== $request->get_param('enabled')) {
301 - $enabled = rest_sanitize_boolean($request->get_param('enabled'));
302 -
303 - // Pro capability. Turning it OFF always works — a lapsed licence
304 - // must never trap the setting in the on position.
305 - if ($enabled && !\ThinkRank\Core\Plan_Config::can('auto_ai_meta', 'ai_visibility')) {
306 - return new WP_REST_Response([
307 - 'success' => false,
308 - 'message' => __('Automatic AI metadata is a ThinkRank Pro feature.', 'thinkrank'),
309 - 'data' => ['requires_pro' => true],
310 - ], 403);
311 - }
312 -
313 - $settings->set('auto_ai_meta_enabled', $enabled);
314 - }
315 - if (null !== $request->get_param('post_types')) {
316 - $settings->set('auto_ai_meta_post_types', (array) $request->get_param('post_types'));
317 - }
318 -
319 - return $this->get_auto_ai();
320 96 }
321 97 }