Skip to chapter content

Chapter 17 3 min read

Don’t Build UI Blindly, Feature Detection

Check before you render; graceful degradation

Every example in this book so far has assumed the feature just works. Fine for learning one concept at a time, not fine for a plugin you’d actually ship. Not every site has an AI provider connected. Not every provider supports every capability. A plugin that renders an “AI Tip” button regardless, then falls over the moment someone clicks it, isn’t handling that reality, it’s just producing a slower, more confusing version of the same failure.

Checking before you commit

is_supported_for_text_generation() (and its siblings for images, speech, and video) answers one question: given this exact configuration, is there a model available that can actually do this? You call it on the builder before generating, not after:

$builder = wp_ai_client_prompt( 'test' )
    ->using_temperature( 0.7 );

if ( $builder->is_supported_for_text_generation() ) {
    // Safe to show text generation UI.
}

Notice it’s the same builder both times, configured once, checked, then generated from if the check passes. That matters: the support check looks at your actual configuration, temperature, system instructions, whatever you’ve chained on, not just “is any model available anywhere.” Build the builder first, check it, then reuse it for the real call, rather than checking a bare builder and generating from a differently-configured one.

This check doesn’t make a network call. It’s matched locally against what’s known about your connected providers’ models, which is why it’s fast and free to run as often as you like, unlike everything else in this book that touches the network.

The same check exists for every modality

is_supported_for_text_generation() isn’t the only one, it’s just the one this chapter demos. Four siblings cover everything else the AI Client can do:

  • is_supported_for_image_generation(), the one you’d actually reach for in Chapters 12 through 14.
  • is_supported_for_text_to_speech_conversion()
  • is_supported_for_speech_generation()
  • is_supported_for_video_generation()

Text-to-speech and video generation aren’t supported by any official provider yet, Module 10 covers them once that changes. But the pattern is identical for all five: build the configuration you intend to use, call the matching is_supported_for_*() method, only proceed if it returns true. Learn it once here and it transfers directly to any modality, including the two this book actually teaches.

Rendering a fallback instead of a failure

Create chapter-17-feature-detection.php inside includes:

<?php
/**
* Chapter 17: Don't Build UI Blindly, Feature Detection
* Usage: add [ai_course_ch17] to any page or post to see the output.
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // No direct access.
}
function ai_course_ch17_feature_detection() {
$builder = wp_ai_client_prompt( 'Write a one-sentence WordPress tip for a beginner.' );
if ( ! $builder->is_supported_for_text_generation() ) {
return '<p><em>AI-powered tips aren\'t available on this site right now, no connected provider supports text generation.</em></p>';
}
$tip = $builder->generate_text();
if ( is_wp_error( $tip ) ) {
return 'Could not generate a tip right now: ' . esc_html( $tip->get_error_message() );
}
return '<p>' . wp_kses_post( $tip ) . '</p>';
}
add_shortcode( 'ai_course_ch17', 'ai_course_ch17_feature_detection' );

Add [ai_course_ch17] to a page and load it. With a provider connected, you get a tip, same as any earlier chapter. To actually see the fallback branch, disconnect your provider the same way you did back in Chapter 3, then reload. Instead of an error, you get a plain, honest message explaining the feature isn’t available right now, not a broken button, not a cryptic failure, just an accurate statement of what’s actually true for this site.

Why this is a different failure mode than is_wp_error()

is_wp_error(), from Chapter 3, catches a call that was attempted and failed. Feature detection is earlier than that; it stops you from attempting something that was never going to work in the first place. Both matter, and they’re not substitutes for each other: a supported feature can still fail at generation time (a network hiccup, a rate limit), and an unsupported feature will never even get that far. A plugin built for real use checks both: support before rendering, errors after generating.

Try it yourself

Wrap Chapter 12’s image-generation shortcode with is_supported_for_image_generation() before its existing logic runs, the same pattern, just the image-specific method instead of the text one. Disconnect your provider and confirm you get a clean fallback message instead of whatever error that chapter’s code produced before you added the check.

This book is created with Chapterwright