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.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 1.0.2 All 50 releases
← All changes | includes/api/class-usage-analytics-endpoint.php +24 -3 2.3.02.9.0 View file →
@@ -329,9 +329,9 @@
329 329 ],
330 330 'provider' => [
331 331 'default' => 'all',
332 332 'type' => 'string',
333 - 'enum' => ['all', 'openai', 'claude', 'gemini', 'openrouter'],
333 + 'enum' => ['all', 'openai', 'claude', 'gemini', 'openrouter', 'openai_compatible'],
334 334 'sanitize_callback' => 'sanitize_key'
335 335 ],
336 336 'user_id' => [
337 337 'default' => 0,
@@ -589,8 +589,12 @@
589 589 'openai' => 0,
590 590 'claude' => 0,
591 591 'gemini' => 0,
592 592 'openrouter' => 0,
593 + // Costed only when the user told us what their endpoint charges;
594 + // otherwise it stays 0 and the UI shows "—" rather than implying
595 + // that a local model was free of charge or that we know the price.
596 + 'openai_compatible' => 0,
593 597 'total' => 0,
594 598 'by_provider' => []
595 599 ];
596 600
@@ -617,9 +621,9 @@
617 621 // get_detailed_usage_breakdown() so both tabs always agree.
618 622 $costs[$provider] += $this->calculate_record_cost($provider, $tokens, $model);
619 623 }
620 624
621 - $costs['total'] = $costs['openai'] + $costs['claude'] + $costs['gemini'] + $costs['openrouter'];
625 + $costs['total'] = $costs['openai'] + $costs['claude'] + $costs['gemini'] + $costs['openrouter'] + $costs['openai_compatible'];
622 626
623 627 // Report only providers that actually incurred cost. Emitting all four
624 628 // unconditionally meant a site with no AI usage rendered four ranked
625 629 // rows at "$0.0000 (0%)" — reading as "four providers were used and
@@ -625,9 +629,9 @@
625 629 // rows at "$0.0000 (0%)" — reading as "four providers were used and
626 630 // each was free" — and made the panel's own "No provider cost data"
627 631 // empty state unreachable.
628 632 $costs['by_provider'] = [];
629 - foreach (['openai', 'claude', 'gemini', 'openrouter'] as $provider) {
633 + foreach (['openai', 'claude', 'gemini', 'openrouter', 'openai_compatible'] as $provider) {
630 634 if ($costs[$provider] <= 0) {
631 635 continue;
632 636 }
633 637
@@ -1223,8 +1227,22 @@
1223 1227 return self::OPENROUTER_PRICING[$model];
1224 1228 }
1225 1229 return self::OPENROUTER_PRICING['openai/gpt-4o-mini'] ?? null;
1226 1230
1231 + case 'openai_compatible':
1232 + // There is no price table for someone else's server: it may be
1233 + // a free local model, an Azure contract or a hosted open model.
1234 + // The only honest number is the one the administrator entered,
1235 + // as a flat per-1M-token rate applied to both directions.
1236 + //
1237 + // Read at report time, so changing the rate (or repointing the
1238 + // provider at another server) re-costs past rows too. Accepted:
1239 + // storing a price per row would mean a schema change for an
1240 + // estimate the administrator typed in the first place.
1241 + $price = (float) \ThinkRank\Core\Settings::instance()->get('openai_compatible_price_per_million', 0);
1242 +
1243 + return $price > 0 ? ['input' => $price, 'output' => $price] : null;
1244 +
1227 1245 default:
1228 1246 return null;
1229 1247 }
1230 1248 }
@@ -1244,8 +1262,11 @@
1244 1262 case 'gemini':
1245 1263 return \ThinkRank\Core\Settings::DEFAULT_GEMINI_MODEL;
1246 1264 case 'openrouter':
1247 1265 return \ThinkRank\Core\Settings::DEFAULT_OPENROUTER_MODEL;
1266 + case 'openai_compatible':
1267 + // Whatever the user pointed us at; there is no default.
1268 + return (string) \ThinkRank\Core\Settings::instance()->get('openai_compatible_model', '');
1248 1269 default:
1249 1270 return 'unknown';
1250 1271 }
1251 1272 }