There is no cost dashboard anywhere in the PHP AI Client SDK. There’s no settings page
that shows how many tokens a site has used this month, no built-in per-feature cost
breakdown, nothing that answers “how much is this feature actually costing us” without
you building the answer yourself. generate_text() returns a plain string, not an
object carrying token counts or a dollar figure. If you want that number, and at real
scale you do, you log every call yourself, to a table you create, and you build the
page that reads it back. That’s the entire subject of this lesson: a real, working cost
log and a plain wp-admin summary page, built from scratch because nothing ships it.
Comfortable calling wp_ai_client_prompt()->generate_text() (Course 3), and basic
familiarity with dbDelta() for creating a custom table and $wpdb for querying it.
Step 1: There’s genuinely nothing to read this off of
Every SDK example across this track shows generate_text() returning a plain string.
There’s no accompanying usage object, no token count, no cost figure attached to that
return value. If you want to know what a call cost, you have to estimate it yourself,
at the point where you have both the prompt and the response in hand, since that’s the
only place this information can be captured at all.
Treat this the same way you’d treat the earlier lessons’ “there is no rate limiter” and “there is no observability handler by default”: the SDK’s job is generating text reliably across providers, not billing reconciliation. Cost tracking is legitimately your application’s responsibility to build, the same way it would be if you were calling any model provider’s API directly without a wrapper at all.
Step 2: A custom table to log every call
Create the table once, on plugin activation, with dbDelta():
// File: my-plugin/class-ai-usage-log.php
function my_plugin_create_ai_usage_table(): void {
global $wpdb;
$table_name = $wpdb->prefix . 'ai_usage_log';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE {$table_name} (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
created_at DATETIME NOT NULL,
feature VARCHAR(100) NOT NULL,
model_used VARCHAR(100) NOT NULL,
estimated_tokens INT UNSIGNED NOT NULL,
estimated_cost_usd DECIMAL(10,5) NOT NULL,
PRIMARY KEY (id),
KEY feature (feature),
KEY created_at (created_at)
) {$charset_collate};";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
register_activation_hook( __FILE__, 'my_plugin_create_ai_usage_table' );
Step 3: Estimate tokens and cost, and log every call through one wrapper
With no usage figure coming back from the SDK, a character-count heuristic is the practical estimate: roughly four characters per token is a reasonable approximation for English text, close enough for a cost dashboard whose job is showing trends and outliers, not producing an invoice-grade figure.
// File: my-plugin/class-ai-usage-log.php
function my_plugin_model_cost_per_1k_tokens(): array {
return array(
'claude-sonnet-4-5' => 0.006,
'gemini-3-pro-preview' => 0.005,
'gpt-5.1' => 0.007,
'default' => 0.006, // fallback if the resolved model isn't in this table
);
}
function my_plugin_estimate_tokens( string $text ): int {
return (int) ceil( strlen( $text ) / 4 );
}
function my_plugin_log_ai_usage( string $feature, string $model_used, string $prompt, string $response ): void {
global $wpdb;
$tokens = my_plugin_estimate_tokens( $prompt ) + my_plugin_estimate_tokens( $response );
$rates = my_plugin_model_cost_per_1k_tokens();
$rate = $rates[ $model_used ] ?? $rates['default'];
$est_cost = ( $tokens / 1000 ) * $rate;
$wpdb->insert(
$wpdb->prefix . 'ai_usage_log',
array(
'created_at' => current_time( 'mysql', true ),
'feature' => $feature,
'model_used' => $model_used,
'estimated_tokens' => $tokens,
'estimated_cost_usd' => $est_cost,
),
array( '%s', '%s', '%s', '%d', '%f' )
);
}
Wrap every AI call through a single function that both generates and logs, so no feature can call the model without also being counted:
// File: my-plugin/class-ai-usage-log.php
function my_plugin_generate_text_tracked( string $feature, string $prompt, string $system_instruction, string $model_hint ) {
$response = wp_ai_client_prompt( $prompt )
->using_system_instruction( $system_instruction )
->using_model_preference( $model_hint )
->generate_text();
if ( is_wp_error( $response ) ) {
return $response;
}
my_plugin_log_ai_usage( $feature, $model_hint, $prompt, $response );
return $response;
}
my_plugin_model_cost_per_1k_tokens() is a static, self-maintained record of what you
believe each model costs per 1,000 tokens, it is not read live from any provider.
Pricing changes over time and varies by provider; if you don’t keep this table current,
every estimate downstream of it drifts quietly out of accuracy. Revisit it on the same
cadence you’d review a provider invoice.
Step 4: A summary page in wp-admin
A minimal admin page that groups the log by day and by feature is enough to answer the question this whole lesson exists to answer, add it under Tools:
// File: my-plugin/class-ai-usage-log.php
add_action( 'admin_menu', function () {
add_management_page(
'AI Usage & Cost',
'AI Usage & Cost',
'manage_options',
'my-plugin-ai-usage',
'my_plugin_render_ai_usage_page'
);
} );
function my_plugin_render_ai_usage_page(): void {
global $wpdb;
$table = $wpdb->prefix . 'ai_usage_log';
$by_feature = $wpdb->get_results(
"SELECT feature, COUNT(*) AS calls, SUM(estimated_tokens) AS tokens, SUM(estimated_cost_usd) AS cost
FROM {$table}
WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
GROUP BY feature
ORDER BY cost DESC"
);
echo '<div class="wrap"><h1>AI Usage & Cost (last 30 days)</h1><table class="widefat striped">';
echo '<thead><tr><th>Feature</th><th>Calls</th><th>Est. Tokens</th><th>Est. Cost (USD)</th></tr></thead><tbody>';
foreach ( $by_feature as $row ) {
printf(
'<tr><td>%s</td><td>%d</td><td>%s</td><td>$%s</td></tr>',
esc_html( $row->feature ),
(int) $row->calls,
esc_html( number_format( (float) $row->tokens ) ),
esc_html( number_format( (float) $row->cost, 4 ) )
);
}
echo '</tbody></table></div>';
}
This is a plain, direct $wpdb query rendered as an HTML table, deliberately not a
charting library or a REST endpoint, since the goal here is a correct, honest number a
site owner can actually read, not a polished product.
Test it
Run a few tracked calls through different features, then load the admin page and confirm the totals match:
wp-env run cli wp eval '
my_plugin_generate_text_tracked( "product-copy", "Write a one-line description for a navy wool scarf.", "Be concise.", "claude-sonnet-4-5" );
my_plugin_generate_text_tracked( "post-summary", "Summarize: This is a test post about caching.", "Be concise.", "gemini-3-pro-preview" );
'
Visit Tools > AI Usage & Cost and confirm both features appear with non-zero estimated tokens and cost.
Recap
Nothing in the PHP AI Client SDK exposes token or cost data, generate_text() returns
text and nothing else, so a cost dashboard is entirely self-built: a custom table
logging feature, model, estimated tokens, and estimated cost per call, a
character-count heuristic standing in for a real usage API, and a plain wp-admin page
summarizing the last 30 days by feature. Keep the per-model cost table current, since
every number downstream depends on it staying accurate.
Resources & further reading
- dbDelta() function reference, developer.wordpress.org
- $wpdb class reference, developer.wordpress.org
- PHP AI Client SDK repository, GitHub