Images

Vision: Analyzing Images for Alt Text and Tagging

⏱ 15 min

Here’s the honest version of this lesson, stated up front rather than buried at the end: as of this writing, there is no confirmed, dedicated method in the WordPress PHP AI Client SDK named something like analyze_image() or describe_image(). Image is listed as a supported input modality for models, and with_file(), the same method used in the previous lesson’s editing example, can attach an image file to a prompt that a vision-capable model then reasons about through the ordinary generate_text() call. That works today. It’s just not a purpose-built vision feature with its own name, it’s the general-purpose file-attachment method doing a job the SDK hasn’t given a dedicated wrapper for yet. This lesson builds on that pattern honestly, and tells you exactly what to check before you rely on it in a shipping product.

What you'll learn in this lesson
Attaching an image to a prompt
with_file(), the same method used for image-editing input in Course 13's first lesson.
Asking a model to describe an image in text
Combining with_file() and with_text() ahead of a normal generate_text() call.
Turning a description into alt text and tags
Prompting for a specific, structured answer rather than a free-form paragraph.
What to verify before shipping this
Why this lesson's pattern could be superseded by a dedicated method at any point.
Prerequisites

Lesson 1 of this course, in particular its use of File objects and with_file()-style input. Course 5’s text generation lessons for generate_text() itself.

No dedicated vision method is confirmed to exist

This lesson’s entire approach rests on with_file() plus generate_text(), not on a named vision feature. If a dedicated method for image analysis ships in a later SDK version, prefer it over this pattern, it will almost certainly handle model-specific quirks (how different providers expect image data formatted, size limits, and so on) more reliably than a hand-rolled prompt does. Check the PHP AI Client SDK repository for newer methods before building this into new code.

Step 1: Attaching an existing image to a prompt

with_file() accepts a File object, the same DTO you saw returned from toImageFile() in the previous lesson, or you can construct one directly from a local path, a URL, or base64 data:

// File: my-plugin/class-image-vision.php
use WordPress\AiClient\Files\DTO\File;

$attachment_path = get_attached_file( $attachment_id );
$mime_type        = get_post_mime_type( $attachment_id );

$file = new File( $attachment_path, $mime_type );

File’s constructor is deliberately flexible, it detects whether the string you passed is a URL, a data URI, plain base64, or a local file path, and stores it accordingly. For an existing media library attachment, passing the local path via get_attached_file() is the simplest option.

Step 2: Asking a model to describe it

With the file built, attach it alongside a text instruction and call generate_text() exactly like you would for a text-only prompt:

// File: my-plugin/class-image-vision.php
$description = wp_ai_client_prompt()
	->with_text( 'Describe this image in one plain sentence suitable for use as alt text. Do not start with "an image of" or "a photo of".' )
	->with_file( $file )
	->generate_text();

The result is a plain string, the same return type generate_text() always gives you. Whether this actually works depends entirely on the underlying model supporting image input, most current-generation frontier models do, but the SDK doesn’t currently expose a way to check “does this specific call support an attached image” the way isSupportedForImageGeneration() lets you check image generation support. Wrap the call in a try/catch and treat a failure as “this provider or model doesn’t support image input” until proven otherwise.

Step 3: Asking for tags in a structured shape

A free-form description is useful for alt text, a flat list of tags is more useful for categorization. Ask for both in the same call rather than making two requests, and lean on the JSON output support already covered in Course 5 to get a shape you can parse reliably instead of splitting a sentence on commas:

// File: my-plugin/class-image-vision.php
$response = wp_ai_client_prompt()
	->with_text(
		'Look at this image and respond with JSON only: ' .
		'{"alt_text": "one plain sentence describing the image", ' .
		'"tags": ["3 to 6 short lowercase keywords describing subject matter"]}'
	)
	->with_file( $file )
	->generate_text();

$parsed = json_decode( $response, true );

if ( ! is_array( $parsed ) || empty( $parsed['alt_text'] ) ) {
	// Model didn't return valid JSON, fall back to a plain description call instead.
	$parsed = array( 'alt_text' => '', 'tags' => array() );
}
No confirmed structured-output guarantee for vision calls

Course 5 covers asOutputSchema() / JSON-mode style output for text generation. Whether that same enforcement is reliable when an image is attached via with_file() hasn’t been confirmed one way or the other here, treat the instruction-based JSON approach above as the safer bet for now, and always validate the parsed result before trusting it, exactly as shown above.

Step 4: Saving the result

Once you have a parsed description and tag list, saving it uses the same core WordPress functions as any other attachment metadata:

// File: my-plugin/class-image-vision.php
function my_plugin_apply_vision_result( int $attachment_id, array $parsed ): void {
	if ( ! empty( $parsed['alt_text'] ) ) {
		update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $parsed['alt_text'] ) );
	}

	if ( ! empty( $parsed['tags'] ) && is_array( $parsed['tags'] ) ) {
		wp_set_object_terms( $attachment_id, array_map( 'sanitize_text_field', $parsed['tags'] ), 'post_tag', true );
	}
}

wp_set_object_terms() with 'post_tag' works on attachments the same way it works on posts, attachments are a post type, taxonomies attach to them the same way. The true final argument appends rather than replaces, so running this again later on the same attachment doesn’t wipe out tags a human added by hand.

Test it: describe a real uploaded image

wp-env run cli wp eval '
$attachment_id = 123; // replace with a real attachment ID from your media library
$path = get_attached_file( $attachment_id );
$mime = get_post_mime_type( $attachment_id );
$file = new WordPress\AiClient\Files\DTO\File( $path, $mime );

$response = wp_ai_client_prompt()
	->with_text( "Describe this image in one plain sentence." )
	->with_file( $file )
	->generate_text();

echo $response . "\n";
'

You should see a plain-text sentence back describing the actual contents of that specific image, not a generic placeholder. If you get an error instead, the configured provider or model likely doesn’t support image input, that’s a real, expected outcome right now, not a bug in your code.

This pattern is a stand-in, not a permanent API

Because there’s no dedicated vision method, there’s also no guarantee this exact with_file() plus generate_text() combination will remain the recommended path once the SDK adds one. Keep vision calls isolated in one function (as shown above) rather than scattered across your plugin, so that when a dedicated method does ship, updating is a one-function change, not a codebase-wide search and replace.

Recap

with_file() attaches an existing image to a prompt, generate_text() then asks a vision-capable model to describe it, this is a real, working pattern today, but it’s built from general-purpose methods, not a dedicated vision feature. Ask for a structured JSON response to get alt text and tags in one call, validate the parsed result before trusting it, and save the outcome with ordinary update_post_meta() and wp_set_object_terms() calls. Treat this lesson’s approach as the current best-available option, and check the SDK’s repository for a purpose-built method before building new production code around it.

Resources & further reading

← Generating Images Into the Media Library Audio Transcription →