Add AI alt text generation using WordPress AI connector - #1742
Add AI alt text generation using WordPress AI connector#1742SteveJonesDev wants to merge 10 commits into
Conversation
Integrates AI-powered alt text suggestions into the issue modal for image alt text violations (img_alt_missing, img_alt_empty, img_alt_invalid). When a supported AI service is configured — either the WordPress AI Client (WP 7.0+ wp_ai_client_prompt) or the AI Services plugin — a collapsible "Generate AI Alt Text" panel appears inside the issue modal. Clicking "Generate Suggestions" sends the image to the connected AI service and returns three distinct alt text options, each focused on a different visual element. Users can review character counts and explanations, then apply a suggestion directly to the media attachment via the WP REST API. On apply, a rescan is queued so the issue status updates automatically. New files: - includes/classes/AI/AltTextGenerator.php — core AI integration class - src/issueModal/components/AltTextPanel.js — React suggestion UI Modified: - includes/classes/class-rest-api.php — POST /accessibility-checker/v1/generate-alt-text endpoint - admin/class-enqueue-admin.php — exposes aiAltAvailable flag to JS - src/issueModal/components/IssueDetailsModal.js — mounts AltTextPanel - src/issueModal/sass/issue-modal.scss — styles for suggestion cards and panel
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds AI-generated alt-text: a backend AltTextGenerator (dual-provider), a POST REST endpoint, a frontend AltTextPanel with apply flows and styles, modal integration, and a localized ChangesAI-Powered Alt-Text Generation
Sequence Diagram(s)sequenceDiagram
participant User
participant Modal as IssueDetailsModal
participant Panel as AltTextPanel
participant REST as REST API
participant Generator as AltTextGenerator
participant MediaAPI as WP Media API
User->>Modal: open issue modal
Modal->>Panel: render AltTextPanel
Panel->>Panel: extract attachment ID from markup
User->>Panel: click Generate Suggestions
Panel->>REST: POST /accessibility-checker/v1/generate-alt-text
REST->>Generator: generate(attachment_id, num_suggestions)
Generator->>Generator: validate, build prompt, call AI provider
Generator->>REST: return suggestions
REST->>Panel: 200 {suggestions: [...]}
Panel->>Panel: display suggestion cards with alt text
User->>Panel: click Apply on a suggestion
Panel->>MediaAPI: POST /wp/v2/media/:id {alt: suggestion}
MediaAPI->>Panel: 200 success
Panel->>Modal: setPendingRescan(true)
User->>Modal: close modal
Modal->>Modal: re-scan issue to update status
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces an AI-powered alt text generation feature for images, integrating with either the WordPress AI connector or the AI Services plugin. It adds a new REST API endpoint, a backend AltTextGenerator class, and a frontend AltTextPanel component within the issue details modal to allow users to generate and apply suggestions. The review feedback highlights two critical areas where defensive checks should be added to handle potential WP_Error returns from wp_ai_client_prompt() and $service->get_model() to prevent runtime errors.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| $model = $service->get_model( | ||
| [ | ||
| 'feature' => 'accessibility-checker-alt-text', | ||
| 'capabilities' => [ 'MULTIMODAL_INPUT', 'TEXT_GENERATION' ], | ||
| ] | ||
| ); |
There was a problem hiding this comment.
The $service->get_model() call can return a WP_Error if no matching model is found or if capabilities are not met. Calling $model->generate_text() on a WP_Error object will result in a fatal error (or a TypeError caught by the Throwable block). We should defensively check if $model is a WP_Error before proceeding.
$model = $service->get_model(
[
'feature' => 'accessibility-checker-alt-text',
'capabilities' => [ 'MULTIMODAL_INPUT', 'TEXT_GENERATION' ],
]
);
if ( is_wp_error( $model ) ) {
return $model;
}| $builder = wp_ai_client_prompt( 'accessibility-checker-alt-text' ); | ||
|
|
||
| if ( method_exists( $builder, 'with_image' ) ) { |
There was a problem hiding this comment.
If wp_ai_client_prompt() returns a WP_Error (e.g., due to configuration issues), calling method_exists or $builder->send() will trigger a PHP error/exception. It is safer and more idiomatic to perform a defensive check using is_wp_error() immediately after retrieving the builder.
$builder = wp_ai_client_prompt( 'accessibility-checker-alt-text' );
if ( is_wp_error( $builder ) ) {
return $builder;
}
if ( method_exists( $builder, 'with_image' ) ) {There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 91aa999624
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await apiFetch( { | ||
| path: `/wp/v2/media/${ attachmentId }`, | ||
| method: 'POST', | ||
| data: { alt_text: altText }, |
There was a problem hiding this comment.
Update the scanned markup when applying alt text
When the issue comes from saved post content such as a Gutenberg or classic image whose HTML already contains alt="" (or a bad alt), this only writes the suggestion to the media attachment record. The scanner checks the rendered DOM attribute in the post content, so the subsequent rescan will still see the same empty/invalid alt in the saved markup and the UI reports success even though the issue is not fixed. The apply path needs to update the block/post markup for the affected image, or only offer this action for images rendered dynamically from attachment metadata.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
includes/classes/class-rest-api.php (1)
379-386: ⚡ Quick winThe
minimumandmaximumproperties are not enforced by WordPress REST API validation.Lines 383-384 define
minimumandmaximumfornum_suggestions, but WordPress REST API does not automatically enforce these constraints. They serve only as schema documentation. The backendAltTextGenerator::generate()already clamps the value (line 63 in AltTextGenerator.php), but adding a validation callback here would provide earlier feedback to API consumers.✅ Proposed fix to enforce range validation
'num_suggestions' => [ 'required' => false, 'type' => 'integer', 'default' => 3, 'minimum' => 1, 'maximum' => 5, + 'validate_callback' => function ( $param ) { + return is_numeric( $param ) && $param >= 1 && $param <= 5; + }, 'sanitize_callback' => 'absint', ],🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@includes/classes/class-rest-api.php` around lines 379 - 386, The schema for 'num_suggestions' in class-rest-api.php documents 'minimum' and 'maximum' but doesn't enforce them; add a validate_callback for the 'num_suggestions' argument (the same array where 'type' => 'integer' and 'sanitize_callback' => 'absint' is defined) that checks the sanitized int is between 1 and 5 and returns true or a WP_Error with a clear message; keep AltTextGenerator::generate() clamping as a fallback but perform this early validation to give API consumers immediate feedback.includes/classes/AI/AltTextGenerator.php (1)
54-56: ⚡ Quick winVerify the attachment is an image, not just any attachment type.
The validation checks
get_post_type( $attachment_id ) === 'attachment'but doesn't verify the attachment is actually an image. Non-image attachments (PDFs, videos, audio files) would pass this check but fail whenwp_get_attachment_image_url()returns false at line 58. Consider adding an explicit mime type check for clarity and better error messages.📸 Proposed fix to validate image mime type
+ if ( ! wp_attachment_is_image( $attachment_id ) ) { + return new \WP_Error( 'not_an_image', __( 'The provided attachment is not an image.', 'accessibility-checker' ) ); + } + if ( 'attachment' !== get_post_type( $attachment_id ) ) { return new \WP_Error( 'invalid_attachment', __( 'The provided ID is not a valid media attachment.', 'accessibility-checker' ) ); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@includes/classes/AI/AltTextGenerator.php` around lines 54 - 56, The current validation in AltTextGenerator (the block checking get_post_type($attachment_id) === 'attachment') only ensures it's an attachment but not that it's an image; update the validation to explicitly confirm the attachment is an image (use wp_attachment_is_image($attachment_id) or check get_post_mime_type($attachment_id) starts with 'image/') and return a distinct WP_Error (e.g., 'invalid_image_attachment') with a clear message when it is not an image before calling wp_get_attachment_image_url(); keep the original post-type check but add this image-type guard in the same method to prevent wp_get_attachment_image_url() from receiving non-image IDs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@includes/classes/AI/AltTextGenerator.php`:
- Line 233: The json_decode call that assigns $data = json_decode( $text, true
); should include an explicit depth limit to avoid DoS from deeply nested JSON;
update the call in AltTextGenerator (the json_decode usage that produces $data)
to pass a depth of 3 (e.g., json_decode(..., true, 3)) so the decoded response
is restricted to the expected shallow structure while preserving associative
arrays.
In `@src/issueModal/components/AltTextPanel.js`:
- Around line 106-117: Reformat the JSDoc block for the AltTextPanel component
so it matches the project's ESLint JSDoc alignment rules: ensure the comment
starts with /** on its own line, every subsequent line begins with " * " (single
space after the asterisk), align the `@param` tags vertically and use a single
space between the type, param name and the hyphen/description, and close the
block with " */" on its own line; apply this to the block documenting
AltTextPanel and its params (props.rule, props.issue, props.isOpen,
props.onToggle).
- Around line 24-104: The SuggestionCard component has ESLint failures: fix the
JSDoc alignment for the SuggestionCard comment block so each tag line lines up;
add missing trailing commas in the multiline JSX expressions (the aria-label
sprintf calls and the className/props lists around the character count and focus
spans — locate the sprintf/aria-label blocks in SuggestionCard to add trailing
commas); and remove the nested ternary used to choose the Button text (inside
Button children around isApplied/isApplying) by computing the label beforehand
(e.g., create a local getButtonLabel or label const above the return and use a
simple conditional or if/else) so the JSX only renders a single variable and the
Spinner remains conditional. Ensure all changes reference the SuggestionCard
function and its Button/aria-label sprintf usages.
---
Nitpick comments:
In `@includes/classes/AI/AltTextGenerator.php`:
- Around line 54-56: The current validation in AltTextGenerator (the block
checking get_post_type($attachment_id) === 'attachment') only ensures it's an
attachment but not that it's an image; update the validation to explicitly
confirm the attachment is an image (use wp_attachment_is_image($attachment_id)
or check get_post_mime_type($attachment_id) starts with 'image/') and return a
distinct WP_Error (e.g., 'invalid_image_attachment') with a clear message when
it is not an image before calling wp_get_attachment_image_url(); keep the
original post-type check but add this image-type guard in the same method to
prevent wp_get_attachment_image_url() from receiving non-image IDs.
In `@includes/classes/class-rest-api.php`:
- Around line 379-386: The schema for 'num_suggestions' in class-rest-api.php
documents 'minimum' and 'maximum' but doesn't enforce them; add a
validate_callback for the 'num_suggestions' argument (the same array where
'type' => 'integer' and 'sanitize_callback' => 'absint' is defined) that checks
the sanitized int is between 1 and 5 and returns true or a WP_Error with a clear
message; keep AltTextGenerator::generate() clamping as a fallback but perform
this early validation to give API consumers immediate feedback.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9f126e93-32d7-45a3-b5f9-bb69c48a19c7
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (6)
admin/class-enqueue-admin.phpincludes/classes/AI/AltTextGenerator.phpincludes/classes/class-rest-api.phpsrc/issueModal/components/AltTextPanel.jssrc/issueModal/components/IssueDetailsModal.jssrc/issueModal/sass/issue-modal.scss
PHP (AltTextGenerator): - Add is_wp_error() guard after wp_ai_client_prompt() call before chaining methods — previously a WP_Error return would cause a fatal TypeError - Add is_wp_error() guard after get_model() call before calling generate_text() on the result for the same reason - Pass depth limit of 3 to json_decode() to cap potential DoS from deeply nested AI responses (expected structure is a flat array of simple objects) JS (AltTextPanel): - After saving alt text to the media attachment record, also update any matching core/image Gutenberg block attribute via the block-editor data store — without this the saved post markup still carried the old (empty/ invalid) alt so a rescan would continue to flag the issue despite the apparent success message
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/issueModal/components/AltTextPanel.js`:
- Around line 189-207: The current findImageBlock function returns only the
first matching core/image block so only one block gets updated; change the logic
to collect all matching blocks (e.g., rename to findImageBlocks or add a
collector) by recursively traversing blockEditorSelect.getBlocks() and gathering
every block where block.name === 'core/image' && block.attributes?.id ===
attachmentId (including matches inside innerBlocks), then iterate over the
collected blocks and call blockEditorDispatch.updateBlockAttributes for each
block.clientId with { alt: altText } so every instance of the attachment is
updated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 1b233891-8795-4cf4-bc51-a9ed9976474e
📒 Files selected for processing (2)
includes/classes/AI/AltTextGenerator.phpsrc/issueModal/components/AltTextPanel.js
🚧 Files skipped from review as they are similar to previous changes (1)
- includes/classes/AI/AltTextGenerator.php
| const findImageBlock = ( blocks ) => { | ||
| for ( const block of blocks ) { | ||
| if ( block.name === 'core/image' && block.attributes?.id === attachmentId ) { | ||
| return block; | ||
| } | ||
| if ( block.innerBlocks?.length ) { | ||
| const found = findImageBlock( block.innerBlocks ); | ||
| if ( found ) { | ||
| return found; | ||
| } | ||
| } | ||
| } | ||
| return null; | ||
| }; | ||
|
|
||
| const imageBlock = findImageBlock( blockEditorSelect.getBlocks() ); | ||
| if ( imageBlock ) { | ||
| blockEditorDispatch.updateBlockAttributes( imageBlock.clientId, { alt: altText } ); | ||
| } |
There was a problem hiding this comment.
Update all matching core/image blocks, not just the first one.
At Line 189, findImageBlock short-circuits on the first match, so only one block gets updated at Line 206. If the same attachment appears multiple times in content, other blocks keep stale alt, and rescans may still fail.
Suggested fix
- const findImageBlock = ( blocks ) => {
+ const findImageBlocks = ( blocks, matches = [] ) => {
for ( const block of blocks ) {
if ( block.name === 'core/image' && block.attributes?.id === attachmentId ) {
- return block;
+ matches.push( block );
}
if ( block.innerBlocks?.length ) {
- const found = findImageBlock( block.innerBlocks );
- if ( found ) {
- return found;
- }
+ findImageBlocks( block.innerBlocks, matches );
}
}
- return null;
+ return matches;
};
- const imageBlock = findImageBlock( blockEditorSelect.getBlocks() );
- if ( imageBlock ) {
- blockEditorDispatch.updateBlockAttributes( imageBlock.clientId, { alt: altText } );
+ const imageBlocks = findImageBlocks( blockEditorSelect.getBlocks() );
+ for ( const imageBlock of imageBlocks ) {
+ blockEditorDispatch.updateBlockAttributes( imageBlock.clientId, { alt: altText } );
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/issueModal/components/AltTextPanel.js` around lines 189 - 207, The
current findImageBlock function returns only the first matching core/image block
so only one block gets updated; change the logic to collect all matching blocks
(e.g., rename to findImageBlocks or add a collector) by recursively traversing
blockEditorSelect.getBlocks() and gathering every block where block.name ===
'core/image' && block.attributes?.id === attachmentId (including matches inside
innerBlocks), then iterate over the collected blocks and call
blockEditorDispatch.updateBlockAttributes for each block.clientId with { alt:
altText } so every instance of the attachment is updated.
Replace the single get_text() check with extract_text_from_response() which tries all known method names across SDK versions in order: get_text, get_first_candidate_text, get_content, camelCase variants, and a get_candidates() traversal. Both the WP AI Client and ai-services paths now share this fallback chain. On failure the error message now includes the actual PHP class name of the unexpected response object to help diagnose mismatched API versions.
The previous implementation used incorrect method names based on assumed API shape. After inspecting the actual Prompt_Builder source: wp_ai_client_prompt(): - First argument is the prompt text (not a feature slug) - Image files go through ->with_file($url, $mimeType), not ->with_image() - Terminate method is ->generate_text() which returns string|WP_Error directly — there is no ->with_message() or ->send() Add get_mime_type() helper that derives MIME type from the image URL's file extension so with_file() gets the correct type hint. ai-services Candidates traversal: - Replace the flat extract_text_from_response() with extract_text_from_candidates() that follows the documented chain: ->get(0)->get_content()->get_parts()->get(0)->get_text() - Keep get_first_candidate_text() and direct string methods as fallbacks for older plugin versions
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
includes/classes/AI/AltTextGenerator.php (2)
35-36:⚠️ Potential issue | 🟠 MajorFix
AltTextGenerator::is_available()so the UI flag doesn’t mean “configured/ready to generate”.
includes/classes/AI/AltTextGenerator.php:35-36only checksfunction_exists()(integration present).admin/class-enqueue-admin.php:215forwards this asaiAltAvailable, andsrc/issueModal/components/AltTextPanel.js:134uses it to render the panel—even when no usable service is configured. In that case,generate()can still fail (e.g.,generate_with_ai_services()returnsWP_Errorcodeno_configured_service).
Makeis_available()(or a new method) validate an actually usable/configured connector/service before returningtrue, or rename the frontend flag to match what the check really guarantees.
217-237:⚠️ Potential issue | 🟠 MajorFix AI Services fallback capability mismatch in AltTextGenerator::generate_with_ai_services()
When the multimodal-capable service lookup fails, the fallback selects a TEXT_GENERATION-only service, but the code still requests a model with
MULTIMODAL_INPUTand sends animage_urlpart. On text-only setups this defers failure to$service->get_model()and returns a lower-level error instead of the intendedno_configured_serviceresponse—either keepMULTIMODAL_INPUTrequirements throughout or implement a real text-only fallback that omitsimage_url/multimodal model requirements.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@includes/classes/AI/AltTextGenerator.php` around lines 217 - 237, The fallback in AltTextGenerator::generate_with_ai_services() currently chooses a TEXT_GENERATION-only service but still later calls $service->get_model() requesting MULTIMODAL_INPUT and sends an image_url, causing misleading lower-level errors; update the logic so that after calling $ai->get_available_service(...) you detect the picked service's capabilities: if it only supports TEXT_GENERATION, call $service->get_model() with capabilities [ 'TEXT_GENERATION' ] and send a text-only prompt (omit image_url and any multimodal parts); otherwise keep the MULTIMODAL_INPUT requirement; also ensure the original no_configured_service WP_Error is still returned when no suitable service exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@includes/classes/AI/AltTextGenerator.php`:
- Around line 166-185: The code in
AltTextGenerator::extract_text_from_response() calls method_exists() on
$response and on $first without ensuring they are objects, which can cause
warnings or exceptions for null/array/scalar SDK responses; update the method to
first verify is_object($response) before looping over $methods and before
calling method_exists(), and when handling candidates ensure $candidates is an
array and that $first is an object (use is_object($first)) before calling
method_exists($first, ...); if those checks fail, return the existing
WP_Error('unexpected_response') path so non-object responses are handled safely.
---
Outside diff comments:
In `@includes/classes/AI/AltTextGenerator.php`:
- Around line 217-237: The fallback in
AltTextGenerator::generate_with_ai_services() currently chooses a
TEXT_GENERATION-only service but still later calls $service->get_model()
requesting MULTIMODAL_INPUT and sends an image_url, causing misleading
lower-level errors; update the logic so that after calling
$ai->get_available_service(...) you detect the picked service's capabilities: if
it only supports TEXT_GENERATION, call $service->get_model() with capabilities [
'TEXT_GENERATION' ] and send a text-only prompt (omit image_url and any
multimodal parts); otherwise keep the MULTIMODAL_INPUT requirement; also ensure
the original no_configured_service WP_Error is still returned when no suitable
service exists.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e95abe31-21a1-4962-81de-e74d43fc98e5
📒 Files selected for processing (1)
includes/classes/AI/AltTextGenerator.php
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
includes/classes/AI/AltTextGenerator.php (1)
35-36:⚠️ Potential issue | 🟠 Major | ⚡ Quick winMake
is_available()reflect usable provider state, not just installed functions.
admin/class-enqueue-admin.phpuses this method to setaiAltAvailable, so a barefunction_exists()check makes the panel render even when no AI service/model is actually configured. In that state the first POST just comes back withno_configured_service, which is a user-visible broken flow. Reuse the same provider/configuration checks here that generation depends on so the UI only advertises the feature when it can succeed.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@includes/classes/AI/AltTextGenerator.php` around lines 35 - 36, is_available() currently only checks for installed helper functions and so advertises the Alt Text UI even when no AI provider/model is configured; change it to return true only when the same provider/configuration checks used by the generation path indicate a usable service. Concretely, update AI/AltTextGenerator::is_available() to call the same configuration/provider helper(s) used by the POST-generation flow (the code path that currently returns "no_configured_service") — e.g. check the ai_services() result for a configured/active provider or call the existing helper that verifies an AI service is configured — and only return true when those checks pass (in addition to any required function_exists checks) so admin/class-enqueue-admin.php's aiAltAvailable reflects an actually usable service.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@includes/classes/AI/AltTextGenerator.php`:
- Around line 126-131: The docblock long description for wp_ai_client_prompt()
in AltTextGenerator.php starts with a lowercase word causing PHPCS failure;
update the long description so its first character is capitalized (e.g., change
"wp_ai_client_prompt()" to "Wp_ai_client_prompt()" or otherwise ensure the first
letter of the long description is uppercase) while leaving the rest of the
signature and builder method lines (->with_file, ->generate_text) unchanged.
- Around line 145-157: The AltTextGenerator currently proceeds to call
generate_text() and parse_suggestions() even when the builder lacks multimodal
support; update the control flow in AltTextGenerator (around the with_file /
generate_text block) to fail fast or explicitly switch to a true text-only mode
when method_exists($builder, 'with_file') is false—return a WP_Error (or a clear
text-only flag) instead of producing image-grounded suggestions; likewise, in
the AI Services selection path (the branch that may fall back to
TEXT_GENERATION), ensure you do NOT attach or send the image_url part when the
chosen service/model is not multimodal (check the selected service/model
capability before adding image parts) and align the public is_available()
implementation to return false unless a multimodal-capable builder/service is
available so the feature isn't advertised when grounding will be downgraded
(reference methods: with_file, generate_text, parse_suggestions, is_available
and the TEXT_GENERATION fallback).
---
Outside diff comments:
In `@includes/classes/AI/AltTextGenerator.php`:
- Around line 35-36: is_available() currently only checks for installed helper
functions and so advertises the Alt Text UI even when no AI provider/model is
configured; change it to return true only when the same provider/configuration
checks used by the generation path indicate a usable service. Concretely, update
AI/AltTextGenerator::is_available() to call the same configuration/provider
helper(s) used by the POST-generation flow (the code path that currently returns
"no_configured_service") — e.g. check the ai_services() result for a
configured/active provider or call the existing helper that verifies an AI
service is configured — and only return true when those checks pass (in addition
to any required function_exists checks) so admin/class-enqueue-admin.php's
aiAltAvailable reflects an actually usable service.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 5d28082e-a401-436c-b8bb-f0bb3af4c3e4
📒 Files selected for processing (1)
includes/classes/AI/AltTextGenerator.php
…ne plugin WP 7.0 built-in AI connector uses send() as terminate method with with_image(), returning GenerativeAiResult. The standalone wp-ai-client plugin uses generate_text() returning a string. Detect which builder variant is present and call the correct terminate method/text extraction path. Also adds robust extract_text_from_result() and text_from_candidate() helpers that handle all three known response shapes (string, ai-services Candidates object with ->get(), WP 7.0 GenerativeAiResult with ->get_candidates() array). https://claude.ai/code/session_01HkDypCgHrgKqBB4cqwnBry
…ctly The WordPress AI connector's with_file() requires a base64 data URI, not a plain URL. Previously we were passing a URL and trying to detect the terminate method via method_exists() before with_file() was called, which always missed generate_text() since the method may not be present on the initial builder object. Now: read the image from disk (or download it) → convert to data URI → call wp_ai_client_prompt($prompt)->with_file($data_uri)->generate_text() directly, matching the pattern used by the WordPress/ai plugin itself. https://claude.ai/code/session_01HkDypCgHrgKqBB4cqwnBry
The full-resolution original can be many MB, causing cURL to time out before Google's API responds. Try local 'large' → 'medium_large' → 'medium' → 'full' sizes in order, stopping at the first readable file. Falls back to downloading the 'large' URL if no local file is found. https://claude.ai/code/session_01HkDypCgHrgKqBB4cqwnBry
Adds a Generate with AI button to the Simplified Summary section of the Readability Analysis panel in the block editor sidebar. Clicking generates a plain-language summary of the post content at or below 8th-grade reading level (WCAG 3.1.5 AAA) using the WordPress AI connector or AI Services plugin. - SimplifiedSummaryGenerator.php: text-only AI generation, processes post content through the same filters used by the readability grade calculator, truncates to 8000 chars to keep latency low - REST endpoint POST /accessibility-checker/v1/generate-simplified-summary - Generate with AI button appears above the textarea when aiAltAvailable; pre-fills the textarea so the user can review before clicking Save Summary https://claude.ai/code/session_01HkDypCgHrgKqBB4cqwnBry
Integrates AI-powered alt text suggestions into the issue modal for
image alt text violations (img_alt_missing, img_alt_empty, img_alt_invalid).
When a supported AI service is configured — either the WordPress AI Client
(WP 7.0+ wp_ai_client_prompt) or the AI Services plugin — a collapsible
"Generate AI Alt Text" panel appears inside the issue modal. Clicking
"Generate Suggestions" sends the image to the connected AI service and
returns three distinct alt text options, each focused on a different visual
element. Users can review character counts and explanations, then apply a
suggestion directly to the media attachment via the WP REST API. On apply,
a rescan is queued so the issue status updates automatically.
New files:
Modified:
Summary by CodeRabbit