Chapter 19
Politely Requesting a Model — Model Preferences
Preference vs. requirement; fallback chain
Every example in this book has used whatever model happens to be configured on the site. Sometimes you’d rather ask for a specific one instead, without requiring it. That’s what using_model_preference() does.
A list, not a demand
using_model_preference() takes a list of model names, in priority order:
$text_result = wp_ai_client_prompt( 'Summarize the history of the printing press.' )
->using_temperature( 0.1 )
->using_model_preference(
'claude-sonnet-4-6',
'gemini-3.1-pro-preview',
'gpt-5.4'
)
->generate_text_result();
The AI Client tries the first name on that list. If the site doesn’t have a provider configured that offers it, it moves to the next, and the next. If none of them match, it falls back to the same default behavior as if you’d never set a preference at all. Your plugin never breaks because a preferred model isn’t present.
That’s the whole point of calling it a preference. Without one, the AI Client just picks the first suitable model it finds among whatever’s configured, not necessarily the best one for your prompt, just the first one it encountered. using_model_preference() lets you nudge that choice without making your plugin depend on any one model actually being there.
Where this actually earns its keep
Chapter 6 hit a real problem: on certain reasoning models, using_temperature() has no effect at all, no error, just quietly ignored. The workaround suggested back then was switching your whole site to a different connected provider, a blunt fix for one feature’s problem.
using_model_preference() is the precise version of that same fix. Instead of changing what your entire site defaults to, you steer just this one call away from a model that ignores temperature, while everything else on the site keeps using whatever’s already configured. A tagline generator, which genuinely needs temperature to do its job, is a good example of exactly when you’d reach for this.
This doesn’t check capability for you
Worth being precise about what the method actually checks: whether a model is connected and available on the site, not whether that model supports every option you’ve chained onto the builder. If a model that ignores temperature happens to be first on your list, the AI Client uses it anyway and lets that setting behave however that model behaves, ignored or otherwise, the exact thing that happened back in Chapter 6.
That means choosing a good list is on you. Model capabilities change often enough that this book can’t promise to stay current on which models support what, so check each provider’s own documentation, OpenAI, Google, Anthropic, for the specific model you’re considering before relying on it for something like temperature or top-p.
Confirming which one actually answered
A preference you can’t verify isn’t worth much. This is exactly what the previous chapter’s result object is for, getProviderMetadata() and getModelMetadata() tell you which one actually responded, whether or not it matched what you asked for.
Create chapter-19-model-preferences.php inside includes:
<?php
/**
* Chapter 19: Politely Requesting a Model, Model Preferences
* Usage: add [ai_course_ch19] to any page or post to see the output.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access.
}
function ai_course_ch19_model_preference() {
// A tagline genuinely needs temperature to do its job, so this
// deliberately steers away from reasoning models that ignore it.
$result = wp_ai_client_prompt( 'Write a short, punchy tagline for a bakery website.' )
->using_temperature( 0.9 )
->using_model_preference( 'gpt-4o', 'claude-sonnet-4-6', 'gemini-3.6-flash' )
->generate_text_result();
if ( is_wp_error( $result ) ) {
return 'Could not generate right now: ' . esc_html( $result->get_error_message() );
}
$text = '';
try {
foreach ( $result->toMessage()->getParts() as $part ) {
if ( null !== $part->getText() ) {
$text .= $part->getText();
}
}
} catch ( Throwable $e ) {
return 'Something went wrong reading the response: ' . esc_html( $e->getMessage() );
}
$provider_metadata = $result->getProviderMetadata();
$model_metadata = $result->getModelMetadata();
$output = '<p>' . wp_kses_post( $text ) . '</p>';
$output .= '<p><strong>Which model actually answered:</strong></p>';
$output .= '<pre style="white-space:pre-wrap; background:#f0f0f0; padding:12px;">';
$output .= 'Provider: ' . esc_html( print_r( $provider_metadata, true ) ) . "\n";
$output .= 'Model: ' . esc_html( print_r( $model_metadata, true ) );
$output .= '</pre>';
return $output;
}
add_shortcode( 'ai_course_ch19', 'ai_course_ch19_model_preference' );
Add [ai_course_ch19] to a page and load it. Below the tagline, you’ll see exactly which provider and model handled it. Reload a few times, and unlike the version of this exact prompt from Chapter 6, you should now see real variation between runs, because the preference steered away from a model that was ignoring temperature in the first place.
Model names don’t stay valid forever
Worth knowing before you rely on this: the exact model name strings, 'gpt-4o', 'gemini-3.6-flash', and so on, are tied to specific point-in-time releases from each provider. Providers rename, retire, and replace models regularly. A preference list that works today can start silently falling through to your second or third choice a few months from now, without any error telling you it happened.
That’s not a flaw in this feature, it’s exactly why it’s a preference and not a requirement. Check what your list is actually resolving to now and then, the same way this chapter’s example does, rather than assuming a model name you wrote once will still be current indefinitely.
Try it yourself
Go back to Chapter 6’s own shortcode and add this same using_model_preference() call to it. Confirm the temperature comparison that used to look identical on your setup now actually shows the difference the chapter was originally trying to demonstrate.