Make WordPress Core

Opened 6 days ago

Last modified 5 days ago

#66244 new enhancement

Improve display of post titles containing HTML in the admin.

Reported by: peterwilsoncc Owned by:
Priority: normal Milestone: Awaiting Review
Component: Posts, Post Types Version:
Severity: normal Keywords: has-patch has-unit-tests
Cc: Focuses:

Description

There was some discussion in #64748 that the display of post titles containing HTML was sub-optimal when viewed within the WordPress dashboard.

The post list table and selected other elements display the tags inline, for example "The page title" is displayed as "The <em>page</em> title".

There wsa some work done in ​PR#11088 but I requested it remain focused on the display of the privacy page link on the front end to allow for further work on the dashboard display in a follow up ticket (this one).

Change History (2)

This ticket was mentioned in ​PR #14019 on ​WordPress/wordpress-develop by ​@shailu25.


6 days ago
#1

  • Keywords has-patch has-unit-tests added; needs-patch removed

Trac ticket: #66244

What

Improves how post titles that contain HTML are displayed in the WordPress admin.

Many admin screens use esc_html() on titles (including _draft_or_post_title()). A title such as The <em>page</em> title is shown as encoded markup (&lt;em&gt;page&lt;/em&gt;) instead of rendered formatting.

This PR:

  • Adds wp_kses_post_title() with a limited allowlist of inline formatting tags.
  • Switches admin title output from esc_html() to wp_kses_post_title() where titles are shown in HTML.
  • Strips tags for aria-label / row-action strings so accessibility text stays plain.

Why

Follow-up to Trac #64748 and ​PR #11088, which scoped the privacy policy link on the front end. Core allows HTML in post titles; the dashboard should render permitted formatting safely instead of showing raw tag text.

How

  • wp_kses_post_title() (src/wp-includes/post-template.php) - wp_kses() allowlist: strong, em, b, i, span (with class), aligned with the privacy policy title approach in trunk.
  • _draft_or_post_title() - returns wp_kses_post_title( $title ) instead of esc_html( $title ).
  • WP_Posts_List_Table / WP_Media_List_Table - the_title filter uses wp_kses_post_title instead of esc_html.
  • Comments admin (comment.php, edit-form-comment.php, WP_Comments_List_Table) - post titles in “In response to” use wp_kses_post_title().
  • Dashboard (dashboard.php) — formatted title in link text; wp_strip_all_tags() for aria-label.
  • A11y / actions — get_primary_column_aria_label(), post/media row actions, and attach labels use stripped titles where attributes must be plain text.

Testing instructions

  1. Create a post titled: The <em class="title">page</em> title.
  2. Posts → All Posts — “page” appears emphasized, not as &lt;em&gt;.
  3. Comments on that post — “In response to” shows formatted title.
  4. Dashboard — Recent drafts/posts show formatted title.
  5. Title with <script>alert(1)</script> — no script in list output.
  6. Confirm row/action aria-label values are plain text (no HTML).

Use of AI Tools

  • Cursor

#2 @therssoftware
5 days ago

### Test & Review Report

Tested ​PR #14019 on trunk.

#### Environment

  • WordPress: 7.2-alpha-63166-src (trunk)
  • PHP: 8.3.33
  • Server: macOS Darwin 24.6.0 (arm64)
  • Database: MariaDB 10.11
  • PHPUnit: 9.6.37
  • PHPCS: 3.13.5 (WordPress-Core)

#### Testing Results

  • Posts List Table (edit.php): Allowed formatting tags (em, strong, b, i, span) now render stylized text inside the title link instead of raw entity text (e.g. &lt;em&gt;).
  • Disallowed & Dangerous Tags: <script>, <iframe>, <img>, and style attributes are cleanly stripped.
  • Accessibility: aria-label attributes across the primary column, row actions, and dashboard links remain clean plain text via wp_strip_all_tags().
  • Comments & Media Tables: Post titles in "In response to" and attachment titles render formatted tags safely.
  • PHPCS: Clean across all modified files.
  • kses.php unit tests: All 403 tests pass cleanly.

#### Notes & Findings on PR #14019

  1. Unit Test Quick-Edit Collision in wpPostsListTable.php: In test_post_title_formatting_tags_are_rendered_in_list_table():
    • The test asserts $this->assertStringNotContainsString( '&lt;em', $output ); on the entire output of render_column_title().
    • This assertion fails because column_title() calls get_inline_data( $post ) for Quick Edit, which intentionally outputs <div class="post_title">The &lt;em class=&quot;title&quot;&gt;page&lt;/em&gt; title</div> so JS can populate the text input.
    • Targeting the assertion specifically to the row title link resolves this: `php $GLOBALSpost = $post; $output = $this->render_column_title( $post, 'list' ); $this->assertStringContainsString( '<a class="row-title" href="' . get_edit_post_link( $post->ID ) . '">The <em class="title">page</em> title</a>', $output ); `
  1. Explicit Parameter Passing in WP_Posts_List_Table: In src/wp-admin/includes/class-wp-posts-list-table.php:
    • Line 1240: $title = _draft_or_post_title();
    • Line 1590: $title = wp_strip_all_tags( _draft_or_post_title() ); Both methods have $post available. Passing $post explicitly (_draft_or_post_title( $post )) avoids reliance on global $post when the list table methods are invoked standalone.

Overall, the approach in PR #14019 is a great UX improvement for admin screens while preserving security and a11y.

Props: therssoftware

---
AI Disclosure: In accordance with the WordPress AI policy, I disclose that generative AI (Google Antigravity) was used in testing and drafting this test report. All test steps, code evaluations, and PHPUnit/PHPCS executions were performed and verified in the local development environment.

Note: See TracTickets for help on using tickets.