Last active
September 28, 2026 14:08
-
-
Save zzap/e45702d27c0f8593355d85d95f7ac202 to your computer and use it in GitHub Desktop.
AI fixes accessibility problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // This is Copilot's response to a following prompt: | |
| // | |
| // "This is the code from a WordPress plugin I have no control over. | |
| // Write code that I can use in my plugin to make this form accessible." | |
| // | |
| // Code can be found here: https://github.com/zzap/WordPress-Gems-for-Devs-Accessibility-with-HTML-API/blob/main/wp-content/plugins/wpgems-inaccessible-blocks/src/blocks/form/save.js | |
| // | |
| import { useBlockProps } from '@wordpress/block-editor'; | |
| import { useInstanceId } from '@wordpress/compose'; | |
| export default function save() { | |
| const instanceId = useInstanceId( save ); | |
| const nameId = `wpgems-form-name-${ instanceId }`; | |
| const emailId = `wpgems-form-email-${ instanceId }`; | |
| const optionsId = `wpgems-form-options-${ instanceId }`; | |
| return ( | |
| <div {...useBlockProps.save()}> | |
| <form> | |
| <p> | |
| <label htmlFor={ nameId }>Name</label> | |
| <input | |
| id={ nameId } | |
| name="name" | |
| type="text" | |
| placeholder="Enter your name" | |
| autoComplete="name" | |
| /> | |
| </p> | |
| <p> | |
| <label htmlFor={ emailId }>Email</label> | |
| <input | |
| id={ emailId } | |
| name="email" | |
| type="email" | |
| autoComplete="email" | |
| /> | |
| </p> | |
| <div> | |
| <label htmlFor={ optionsId }>Select an option:</label> | |
| <select id={ optionsId } name="options"> | |
| <option value="1">Option 1</option> | |
| <option value="2">Option 2</option> | |
| </select> | |
| </div> | |
| <button type="submit">Submit</button> | |
| </form> | |
| </div> | |
| ); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * This is Copilot's second attempt to modify plugin's output, the prompt: | |
| * | |
| * "How is that modifying the plugin's output? | |
| * I need to use this other plugin with an inaccessible form, but I need to modify its output | |
| * without modifying its files." | |
| */ | |
| /** | |
| * Codepilot says: | |
| * "If the form is already on the page and you only need a frontend accessibility patch, use JS instead. | |
| * | |
| * Why this works: | |
| * - You’re not editing the third-party plugin files. | |
| * - You’re overriding/repairing the rendered output in a WordPress-safe hook. | |
| * - This preserves the plugin while fixing the accessibility issue." | |
| */ | |
| document.addEventListener( 'DOMContentLoaded', () => { | |
| document.querySelectorAll( '.wp-block-wpgems-inaccessible-blocks-form form' ).forEach( ( form, formIndex ) => { | |
| const nameInput = form.querySelector( 'input[name="name"]' ); | |
| const emailInput = form.querySelector( 'input[name="email"]' ); | |
| const select = form.querySelector( 'select[name="options"]' ); | |
| if ( nameInput ) { | |
| nameInput.id = `name-${ formIndex }`; | |
| const label = document.createElement( 'label' ); | |
| label.setAttribute( 'for', nameInput.id ); | |
| label.textContent = 'Name'; | |
| nameInput.before( label ); | |
| } | |
| if ( emailInput ) { | |
| emailInput.id = `email-${ formIndex }`; | |
| const label = document.createElement( 'label' ); | |
| label.setAttribute( 'for', emailInput.id ); | |
| label.textContent = 'Email'; | |
| emailInput.before( label ); | |
| } | |
| if ( select ) { | |
| select.id = `options-${ formIndex }`; | |
| const label = document.createElement( 'label' ); | |
| label.setAttribute( 'for', select.id ); | |
| label.textContent = 'Select an option:'; | |
| select.before( label ); | |
| } | |
| } ); | |
| } ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * This is Copilot's second attempt to modify plugin's output, the prompt: | |
| * | |
| * "How is that modifying the plugin's output? | |
| * I need to use this other plugin with an inaccessible form, but I need to modify its output | |
| * without modifying its files." | |
| */ | |
| /** | |
| * Codepilot says: | |
| * "Best approach: filter the block output in WordPress. | |
| * If the plugin is a block and the HTML later gets re-rendered server-side, this is the cleanest non-invasive fix." | |
| */ | |
| /** | |
| * Plugin Name: My Accessible Form Patcher | |
| */ | |
| add_filter( 'render_block', function( $block_content, $block ) { | |
| if ( empty( $block['blockName'] ) || 'wpgems-inaccessible-blocks/form' !== $block['blockName'] ) { | |
| return $block_content; | |
| } | |
| $dom = new DOMDocument(); | |
| libxml_use_internal_errors( true ); | |
| $dom->loadHTML( '<?xml encoding="utf-8" ?>' . $block_content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD ); | |
| $form = $dom->getElementsByTagName( 'form' )->item( 0 ); | |
| if ( ! $form ) { | |
| return $block_content; | |
| } | |
| $fields = $form->getElementsByTagName( 'input' ); | |
| $index = 0; | |
| foreach ( $fields as $field ) { | |
| $id = 'form-field-' . $index++; | |
| if ( 'name' === $field->getAttribute( 'name' ) ) { | |
| $field->setAttribute( 'id', $id ); | |
| $field->setAttribute( 'autocomplete', 'name' ); | |
| } | |
| if ( 'email' === $field->getAttribute( 'name' ) ) { | |
| $field->setAttribute( 'id', $id ); | |
| $field->setAttribute( 'autocomplete', 'email' ); | |
| } | |
| } | |
| $select = $dom->getElementsByTagName( 'select' )->item( 0 ); | |
| if ( $select ) { | |
| $select->setAttribute( 'id', 'form-options-' . wp_unique_id() ); | |
| } | |
| $labels = $dom->getElementsByTagName( 'label' ); | |
| foreach ( $labels as $label ) { | |
| $label->setAttribute( 'for', $label->getAttribute( 'for' ) ?: 'form-field-0' ); | |
| } | |
| return $dom->saveHTML(); | |
| }, 10, 2 ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * This is Copilot's third attempt to modify plugin's output, with the following prompt: | |
| * | |
| * "Why not using some of WordPress' API for this? For example, the HTML API?" | |
| */ | |
| /** | |
| * Codepilot says: | |
| * Because this is not a “database / WP API” problem; it is a “final rendered HTML” problem. | |
| * | |
| * The JS in save.js is the block’s saved markup. If you cannot change that plugin’s code, | |
| * the idiomatic WordPress way is to mutate the rendered HTML after it is generated, not to edit the third-party source. | |
| * | |
| * Use the WordPress HTML API, especially WP_HTML_Tag_Processor, inside a render_block filter. | |
| * It is safer and cleaner than regex or DOMDocument for WordPress HTML. | |
| * | |
| * Why this is the right approach: | |
| * - It avoids modifying the third-party plugin files. | |
| * - It uses WordPress-native HTML parsing instead of string surgery. | |
| * - It preserves accessibility without breaking the block’s HTML structure. | |
| * | |
| * Note: | |
| * - save.js itself is still the author’s source of truth for the block markup. | |
| * - If the plugin later changes its block or markup, this filter should be adjusted. | |
| * - For true <label for="..."> associations, you’d ideally add real label elements, but aria-label is a valid fallback when you cannot alter the original markup cleanly. | |
| * | |
| */ | |
| add_filter( 'render_block', function( $block_content, $block ) { | |
| if ( ( $block['blockName'] ?? '' ) !== 'wpgems-inaccessible-blocks/form' ) { | |
| return $block_content; | |
| } | |
| $processor = new WP_HTML_Tag_Processor( $block_content ); | |
| while ( $processor->next_tag() ) { | |
| $tag = $processor->get_tag(); | |
| $name = $processor->get_attribute( 'name' ); | |
| if ( 'input' === $tag && 'name' === $name ) { | |
| $processor->set_attribute( 'id', 'wpgems-name' ); | |
| $processor->set_attribute( 'autocomplete', 'name' ); | |
| $processor->set_attribute( 'aria-label', 'Name' ); | |
| } | |
| if ( 'input' === $tag && 'email' === $name ) { | |
| $processor->set_attribute( 'id', 'wpgems-email' ); | |
| $processor->set_attribute( 'autocomplete', 'email' ); | |
| $processor->set_attribute( 'aria-label', 'Email' ); | |
| } | |
| if ( 'select' === $tag && 'options' === $name ) { | |
| $processor->set_attribute( 'id', 'wpgems-options' ); | |
| $processor->set_attribute( 'aria-label', 'Select an option' ); | |
| } | |
| } | |
| return $processor->get_updated_html(); | |
| }, 10, 2 ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment