Skip to content

Administration: Strip escaped HTML from list table aria-labels - #12710

Open
itzmekhokan wants to merge 1 commit into
WordPress:trunkfrom
itzmekhokan:fix/65729-strip-escaped-html-in-attributes
Open

Administration: Strip escaped HTML from list table aria-labels#12710
itzmekhokan wants to merge 1 commit into
WordPress:trunkfrom
itzmekhokan:fix/65729-strip-escaped-html-in-attributes

Conversation

@itzmekhokan

Copy link
Copy Markdown

Some of the values used in list table aria-label attributes reach the attribute with their HTML already escaped, so screen readers announce the markup as literal text.

What the problem was:

  • The attachment and post titles are escaped by _draft_or_post_title(), and the link name is escaped by WP_Links_List_Table::display_rows(). Some of these values are also stored in the database with any HTML already escaped.
  • esc_attr() does not double encode, so the escaped HTML survives into the attribute. The browser decodes it back and the accessible name becomes Edit "my<div>image" instead of Edit "myimage".

What the fix does:

  • Decodes entities with html_entity_decode() before calling wp_strip_all_tags(), so the HTML can be detected and removed, in WP_Media_List_Table::handle_row_actions(), WP_Posts_List_Table::handle_row_actions(), and WP_Links_List_Table::column_name().
  • The displayed link name is intentionally left unchanged; only the aria-label value is cleaned.

Approach and why:

  • This follows the pattern already established in core by WP_REST_URL_Details_Controller::prepare_metadata_for_output(), rather than introducing a new formatting helper. The ticket raises a helper as a possibility ("maybe a new formatting helper function could be handy"), but that is a new public API worth deciding separately with committer input, so this patch keeps the change to the affected call sites only.
  • The site title (blogname) case named in the ticket is not currently used in any trunk list table attribute, so nothing is changed for it here.
  • Term names are left alone, as they are already sanitized via sanitize_term() on creation and update.

Trac ticket: https://core.trac.wordpress.org/ticket/65729

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.8
Used for: Ticket analysis, tests and writing PR description.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

Copilot AI review requested due to automatic review settings July 27, 2026 11:26
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props khokansardar.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

The attachment, post and link names used in the row action `aria-label`
attributes are escaped before use: by `_draft_or_post_title()` for posts
and attachments, and by `WP_Links_List_Table::display_rows()` for links.
Some of these values are also stored with any HTML already escaped.

Because `esc_attr()` does not double encode, that escaped HTML survives
into the attribute, and screen readers announce it as literal markup,
for example `Edit "my<div>image"`.

Decode the entities before calling `wp_strip_all_tags()` so the HTML can
be detected and removed, following the pattern already used by
`WP_REST_URL_Details_Controller::prepare_metadata_for_output()`.

The displayed link name is intentionally left unchanged.

Fixes #65729.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves accessibility in wp-admin list tables by preventing escaped HTML fragments in titles/names from being announced literally by screen readers when used in row-action aria-label attributes.

Changes:

  • Decode HTML entities and strip tags before building row-action aria-label values in Posts and Media list tables.
  • Clean only the aria-label value (not the displayed text) for link names in the Links list table.
  • Add PHPUnit coverage to ensure escaped HTML is removed from these aria-label attributes.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/wp-admin/includes/class-wp-posts-list-table.php Decodes entities then strips tags from the post title before composing row-action aria-label strings.
src/wp-admin/includes/class-wp-media-list-table.php Decodes entities then strips tags from the attachment title before composing row-action aria-label strings.
src/wp-admin/includes/class-wp-links-list-table.php Introduces a cleaned name variant for aria-label while leaving the displayed link name unchanged.
tests/phpunit/tests/admin/wpPostsListTable.php Adds a test asserting escaped HTML is removed from Posts list table row-action aria-labels.
tests/phpunit/tests/admin/wpMediaListTable.php Adds a test asserting escaped HTML is removed from Media list table row-action aria-labels.
tests/phpunit/tests/admin/wpLinksListTable.php Adds a new test file validating link-name aria-label cleaning without changing visible output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@itzmekhokan
itzmekhokan force-pushed the fix/65729-strip-escaped-html-in-attributes branch from b137090 to 8b476c1 Compare July 27, 2026 11:36
Copilot AI review requested due to automatic review settings July 27, 2026 11:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants