diff --git a/src/wp-admin/includes/class-wp-application-passwords-list-table.php b/src/wp-admin/includes/class-wp-application-passwords-list-table.php index 9a60853016fc5..b3dccaf478a83 100644 --- a/src/wp-admin/includes/class-wp-application-passwords-list-table.php +++ b/src/wp-admin/includes/class-wp-application-passwords-list-table.php @@ -214,7 +214,12 @@ public function print_js_template_row() { $classes .= ' hidden'; } - printf( '', esc_attr( $classes ), esc_attr( wp_strip_all_tags( $display_name ) ) ); + // The primary column is a `` row header, matching the + // server-rendered markup in WP_List_Table::single_row_columns(). + $tag = $is_primary ? 'th' : 'td'; + $scope = $is_primary ? ' scope="row"' : ''; + + printf( '<%1$s class="%2$s" data-colname="%3$s"%4$s>', $tag, esc_attr( $classes ), esc_attr( wp_strip_all_tags( $display_name ) ), $scope ); switch ( $column_name ) { case 'name': @@ -259,7 +264,7 @@ public function print_js_template_row() { ''; } - echo ''; + echo ""; } echo ''; diff --git a/tests/phpunit/tests/admin/wpApplicationPasswordsListTable.php b/tests/phpunit/tests/admin/wpApplicationPasswordsListTable.php new file mode 100644 index 0000000000000..2c6eda10b050d --- /dev/null +++ b/tests/phpunit/tests/admin/wpApplicationPasswordsListTable.php @@ -0,0 +1,59 @@ +table = _get_list_table( + 'WP_Application_Passwords_List_Table', + array( 'screen' => 'application-passwords-user' ) + ); + } + + /** + * Ensures the JavaScript row template used for a password created via AJAX + * renders the primary column as a `` row header, matching + * the server-rendered markup from WP_List_Table::single_row_columns(). + * + * @ticket 65707 + * + * @covers WP_Application_Passwords_List_Table::print_js_template_row + */ + public function test_print_js_template_row_uses_th_row_header_for_primary_column() { + ob_start(); + $this->table->print_js_template_row(); + $html = ob_get_clean(); + + // Assert on the tag structure and `scope="row"` rather than the localized + // column label, so the test does not depend on the current locale or on + // filters that adjust the column headers. + $this->assertMatchesRegularExpression( + '//', + $html, + 'The primary column should be rendered as a row header.' + ); + + $this->assertStringNotContainsString( + ' cells.' + ); + } +}