Skip to content

Commit 1007a48

Browse files
authored
Merge branch 'WordPress:trunk' into trunk
2 parents 4b83198 + 54b41a8 commit 1007a48

6 files changed

Lines changed: 146 additions & 71 deletions

File tree

src/js/_enqueues/wp/wp-tooltip.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
let openTimeout;
1515

1616
popovers.forEach( function( popover ) {
17-
const trigger = /** @type {HTMLButtonElement|null} */ ( popover.querySelector( 'button.wp-tooltip__toggle' ) );
17+
const trigger = /** @type {HTMLButtonElement|HTMLAnchorElement|null} */ ( popover.querySelector( '.wp-tooltip__toggle' ) );
1818
const panel = /** @type {HTMLSpanElement|null} */ ( popover.querySelector( 'span.wp-tooltip__bubble' ) );
19+
1920
if ( ! trigger || ! panel ) {
2021
return;
2122
}

src/wp-admin/css/wp-tooltip.css

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
.wp-tooltip {
44
display: inline-flex;
55
align-items: center;
6-
vertical-align: middle;
76
}
87

98
/* Toggle and close buttons. */
@@ -22,14 +21,14 @@
2221
cursor: pointer;
2322
}
2423

25-
.wp-tooltip .wp-tooltip__toggle:hover,
26-
.wp-tooltip .wp-tooltip__toggle:focus,
24+
.wp-tooltip:not(:has(button[aria-disabled="true"],button[disabled])) .wp-tooltip__toggle:hover,
25+
.wp-tooltip:not(:has(button[aria-disabled="true"],button[disabled])) .wp-tooltip__toggle:focus,
2726
.wp-tooltip .wp-tooltip__close:hover,
2827
.wp-tooltip .wp-tooltip__close:focus {
2928
color: var(--wp-admin-theme-color, #3858e9);
3029
}
3130

32-
.wp-tooltip .wp-tooltip__toggle:focus,
31+
.wp-tooltip:not(:has(button[aria-disabled="true"],button[disabled])) .wp-tooltip__toggle:focus,
3332
.wp-tooltip .wp-tooltip__close:focus {
3433
outline: 2px solid transparent;
3534
box-shadow: 0 0 0 var(--wp-admin-border-width-focus, 1.5px) var(--wp-admin-theme-color, #3858e9);

src/wp-admin/includes/template.php

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1372,10 +1372,10 @@ function do_meta_boxes( $screen, $context, $data_object ) {
13721372
++$i;
13731373
// get_hidden_meta_boxes() doesn't apply in the block editor.
13741374
$hidden_class = ( ! $screen->is_block_editor() && in_array( $box['id'], $hidden, true ) ) ? ' hide-if-js' : '';
1375-
echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes( $box['id'], $page ) . $hidden_class . '" ' . '>' . "\n";
1375+
echo '<div id="' . $box['id'] . '" class="postbox ' . postbox_classes( $box['id'], $page ) . $hidden_class . '" ' . ' role="region" aria-label="' . esc_attr( wp_strip_all_tags( $box['title'] ) ) . '">' . "\n";
13761376

13771377
echo '<div class="postbox-header">';
1378-
echo '<h2 class="hndle">';
1378+
echo '<h2 class="hndle" id="' . $box['id'] . '-title">';
13791379
if ( 'dashboard_php_nag' === $box['id'] ) {
13801380
echo '<span aria-hidden="true" class="dashicons dashicons-warning"></span>';
13811381
echo '<span class="screen-reader-text">' .
@@ -1397,40 +1397,35 @@ function do_meta_boxes( $screen, $context, $data_object ) {
13971397

13981398
echo '<div class="handle-actions hide-if-no-js">';
13991399

1400-
echo '<button type="button" class="handle-order-higher" aria-disabled="false" aria-describedby="' . $box['id'] . '-handle-order-higher-description">';
1401-
echo '<span class="screen-reader-text">' .
1402-
/* translators: Hidden accessibility text. */
1403-
__( 'Move up' ) .
1404-
'</span>';
1405-
echo '<span class="order-higher-indicator" aria-hidden="true"></span>';
1406-
echo '</button>';
1407-
echo '<span class="hidden" id="' . $box['id'] . '-handle-order-higher-description">' . sprintf(
1408-
/* translators: %s: Meta box title. */
1409-
__( 'Move %s box up' ),
1410-
$widget_title
1411-
) . '</span>';
1412-
1413-
echo '<button type="button" class="handle-order-lower" aria-disabled="false" aria-describedby="' . $box['id'] . '-handle-order-lower-description">';
1414-
echo '<span class="screen-reader-text">' .
1415-
/* translators: Hidden accessibility text. */
1416-
__( 'Move down' ) .
1417-
'</span>';
1418-
echo '<span class="order-lower-indicator" aria-hidden="true"></span>';
1419-
echo '</button>';
1420-
echo '<span class="hidden" id="' . $box['id'] . '-handle-order-lower-description">' . sprintf(
1421-
/* translators: %s: Meta box title. */
1422-
__( 'Move %s box down' ),
1423-
$widget_title
1424-
) . '</span>';
1425-
1426-
echo '<button type="button" class="handlediv" aria-expanded="true">';
1427-
echo '<span class="screen-reader-text">' . sprintf(
1428-
/* translators: %s: Hidden accessibility text. Meta box title. */
1429-
__( 'Show or hide panel: %s' ),
1430-
$widget_title
1431-
) . '</span>';
1432-
echo '<span class="toggle-indicator" aria-hidden="true"></span>';
1433-
echo '</button>';
1400+
$move_up_button = '<button type="button" class="handle-order-higher" aria-describedby="' . $box['id'] . '-title">
1401+
<span class="screen-reader-text">' . __( 'Move up' ) . '</span>
1402+
<span class="order-higher-indicator" aria-hidden="true"></span>
1403+
</button>';
1404+
$move_up_args = array(
1405+
'id' => $box['id'] . '-handle-order-higher-description',
1406+
'button' => $move_up_button,
1407+
);
1408+
echo wp_get_tooltip( __( 'Move up' ), $move_up_args );
1409+
1410+
$move_down_button = '<button type="button" class="handle-order-lower" aria-describedby="' . $box['id'] . '-title">
1411+
<span class="screen-reader-text">' . __( 'Move down' ) . '</span>
1412+
<span class="order-lower-indicator" aria-hidden="true"></span>
1413+
</button>';
1414+
$move_down_args = array(
1415+
'id' => $box['id'] . '-handle-order-lower-description',
1416+
'button' => $move_down_button,
1417+
);
1418+
echo wp_get_tooltip( __( 'Move down' ), $move_down_args );
1419+
1420+
$show_hide_button = '<button type="button" class="handlediv" aria-expanded="true" aria-describedby="' . $box['id'] . '-title">
1421+
<span class="screen-reader-text">' . __( 'Show or hide panel' ) . '</span>
1422+
<span class="toggle-indicator" aria-hidden="true"></span>
1423+
</button>';
1424+
$show_hide_args = array(
1425+
'id' => $box['id'] . '-handlediv',
1426+
'button' => $show_hide_button,
1427+
);
1428+
echo wp_get_tooltip( __( 'Show or hide panel' ), $show_hide_args );
14341429

14351430
echo '</div>';
14361431
}

src/wp-includes/general-template.php

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ function get_search_form( $args = array() ) {
373373
/**
374374
* Retrieves the markup for an accessible tooltip.
375375
*
376-
* Returns a button with an accessible name popover.
376+
* Returns a button with an accessible name popover hint.
377377
*
378378
* @since 7.1.0
379379
*
@@ -383,6 +383,8 @@ function get_search_form( $args = array() ) {
383383
*
384384
* @type string $id Unique ID for the popover element. Default is a
385385
* generated unique ID.
386+
* @type string $button Existing `button` or `a` markup. Used instead of generated button.
387+
* Default standard button HTML.
386388
* @type string $label Not used for tooltips.
387389
* @type string $close_label Not used for tooltips.
388390
* @type string $icon Dashicons icon class for the toggle button.
@@ -399,12 +401,9 @@ function wp_get_tooltip( $content, $args = array() ) {
399401
}
400402

401403
/**
402-
* Retrieves the markup for an accessible tooltip or toggletip.
404+
* Retrieves the markup for an accessible toggle tip.
403405
*
404-
* Returns a button and either a hover/focus triggered tooltip popover or an action
405-
* triggered toggle tip. Enqueue the `wp-tooltip` style and script where it is used.
406-
* Tooltips are used to show the accessible name of a control.
407-
* Toggletips are be used for longer supporting text explaining context.
406+
* Returns a button and an action triggered toggle tip with `$content`.
408407
*
409408
* @since 7.1.0
410409
*
@@ -414,6 +413,8 @@ function wp_get_tooltip( $content, $args = array() ) {
414413
*
415414
* @type string $id Unique ID for the popover element. Default is a
416415
* generated unique ID.
416+
* @type string $button Existing `button` markup. Used instead of generated button.
417+
* Default standard button HTML.
417418
* @type string $label Accessible label for the toggle button.
418419
* Default 'Help', matching the default icon.
419420
* Ignored for tooltips.
@@ -424,9 +425,9 @@ function wp_get_tooltip( $content, $args = array() ) {
424425
* @type string $class Additional class(es) for the wrapping element.
425426
* Default empty.
426427
* }
427-
* @return string Tooltip HTML markup, or an empty string when no content is provided.
428+
* @return string Toggletip HTML markup, or an empty string when no content is provided.
428429
*/
429-
function wp_get_toggletip( $content, $args ) {
430+
function wp_get_toggletip( $content, $args = array() ) {
430431
$args['type'] = 'toggletip';
431432
return wp_get_tooltip_helper( $content, $args );
432433
}
@@ -447,6 +448,8 @@ function wp_get_toggletip( $content, $args ) {
447448
*
448449
* @type string $id Unique ID for the popover element. Default is a
449450
* generated unique ID.
451+
* @type string $button Existing `button` or `a` markup. Used instead of generated button.
452+
* Default standard button HTML.
450453
* @type string $label Accessible label for the toggle button.
451454
* Default 'Help', matching the default icon.
452455
* Ignored for tooltips.
@@ -469,7 +472,8 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
469472
}
470473

471474
$defaults = array(
472-
'id' => '',
475+
'id' => wp_unique_id( 'wp-tooltip-' ),
476+
'button' => '<button type="button" aria-label="%3$s"><span class="dashicons %4$s" aria-hidden="true"></span></button>',
473477
'label' => __( 'Help' ),
474478
'close_label' => __( 'Close' ),
475479
'icon' => 'dashicons-editor-help',
@@ -479,14 +483,43 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
479483

480484
$args = wp_parse_args( $args, $defaults );
481485

482-
$id = '' !== $args['id'] ? $args['id'] : wp_unique_id( 'wp-tooltip-' );
483-
484486
$classes = ( 'tooltip' === $args['type'] ) ? 'wp-tooltip wp-is-tooltip' : 'wp-tooltip wp-is-toggletip';
485487
if ( '' !== $args['class'] ) {
486488
$classes .= ' ' . $args['class'];
487489
}
488490

489-
$icon = '' !== $args['icon'] ? ' ' . $args['icon'] : '';
491+
$icon = ( $args['icon'] ) ? trim( $args['icon'] ) : $defaults['icon'];
492+
$id = ( $args['id'] ) ? $args['id'] : $defaults['id'];
493+
$button = ( $args['button'] ) ? $args['button'] : $defaults['button'];
494+
$processed = false;
495+
$processor = new WP_HTML_Tag_Processor( $button );
496+
if ( true === $processor->next_tag( 'button' ) ) {
497+
$processor->add_class( 'wp-tooltip__toggle' );
498+
if ( 'tooltip' !== $args['type'] ) {
499+
$processor->set_attribute( 'popovertarget', '%2$s' );
500+
$processor->set_attribute( 'aria-haspopup', 'dialog' );
501+
}
502+
$button = $processor->get_updated_html();
503+
$processed = true;
504+
} else {
505+
// Reset processor.
506+
$processor = new WP_HTML_Tag_Processor( $button );
507+
if ( true === $processor->next_tag( 'a' ) && 'tooltip' === $args['type'] ) {
508+
$processor->add_class( 'wp-tooltip__toggle' );
509+
$button = $processor->get_updated_html();
510+
$processed = true;
511+
}
512+
}
513+
if ( ! $processed ) {
514+
// Button HTML passed was not valid.
515+
$processor = new WP_HTML_Tag_Processor( $defaults['button'] );
516+
$processor->add_class( 'wp-tooltip__toggle' );
517+
if ( 'tooltip' !== $args['type'] ) {
518+
$processor->set_attribute( 'popovertarget', '%2$s' );
519+
$processor->set_attribute( 'aria-haspopup', 'dialog' );
520+
}
521+
$button = $processor->get_updated_html();
522+
}
490523

491524
/*
492525
* The markup only uses phrasing content so it is valid when nested
@@ -498,11 +531,9 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
498531
// Tooltips are only used to visually display labels.
499532
$label = wp_strip_all_tags( $content, true );
500533
$markup = sprintf(
501-
'<span class="%1$s">' .
502-
'<button type="button" class="wp-tooltip__toggle" popovertarget="%2$s" aria-label="%3$s">' .
503-
'<span class="dashicons%4$s" aria-hidden="true"></span>' .
504-
'</button>' .
505-
'<span popover="hint" id="%2$s" class="wp-tooltip__bubble" role="tooltip">' .
534+
'<span class="%1$s">
535+
' . $button . '
536+
<span popover="hint" id="%2$s" class="wp-tooltip__bubble" role="tooltip">' .
506537
'<span id="%2$s-text" class="wp-tooltip__text">%5$s</span>' .
507538
'</span>' .
508539
'</span>',
@@ -519,11 +550,9 @@ function wp_get_tooltip_helper( $content, $args = array() ) {
519550
* attributes reproduce the accessible name and focus handling of the native element.
520551
*/
521552
$markup = sprintf(
522-
'<span class="%1$s">' .
523-
'<button type="button" class="wp-tooltip__toggle" popovertarget="%2$s" aria-label="%3$s" aria-haspopup="dialog">' .
524-
'<span class="dashicons%4$s" aria-hidden="true"></span>' .
525-
'</button>' .
526-
'<span popover="auto" id="%2$s" class="wp-tooltip__bubble" role="dialog" aria-label="%3$s" tabindex="-1" autofocus>' .
553+
'<span class="%1$s">
554+
' . $button . '
555+
<span popover="auto" id="%2$s" class="wp-tooltip__bubble" role="dialog" aria-label="%3$s" tabindex="-1" autofocus>' .
527556
'<span id="%2$s-text" class="wp-tooltip__text">%5$s</span>' .
528557
'<button type="button" class="wp-tooltip__close" popovertarget="%2$s" popovertargetaction="hide" aria-label="%6$s">' .
529558
'<span class="dashicons dashicons-no-alt" aria-hidden="true"></span>' .

src/wp-includes/script-loader.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ function wp_default_scripts( $scripts ) {
14391439

14401440
$scripts->add( 'xfn', "/wp-admin/js/xfn$suffix.js", array( 'jquery' ), false, 1 );
14411441

1442-
$scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array( 'jquery-ui-sortable', 'wp-a11y' ), false, 1 );
1442+
$scripts->add( 'postbox', "/wp-admin/js/postbox$suffix.js", array( 'jquery-ui-sortable', 'wp-a11y', 'wp-tooltip' ), false, 1 );
14431443
$scripts->set_translations( 'postbox' );
14441444

14451445
$scripts->add( 'tags-box', "/wp-admin/js/tags-box$suffix.js", array( 'jquery', 'tags-suggest' ), false, 1 );
@@ -1638,7 +1638,7 @@ function wp_default_styles( $styles ) {
16381638
$styles->add( 'code-editor', "/wp-admin/css/code-editor$suffix.css", array( 'wp-codemirror' ) );
16391639
$styles->add( 'site-health', "/wp-admin/css/site-health$suffix.css" );
16401640

1641-
$styles->add( 'wp-admin', false, array( 'dashicons', 'common', 'forms', 'admin-menu', 'dashboard', 'list-tables', 'edit', 'revisions', 'media', 'themes', 'about', 'nav-menus', 'widgets', 'site-icon', 'l10n', 'wp-base-styles' ) );
1641+
$styles->add( 'wp-admin', false, array( 'dashicons', 'common', 'forms', 'admin-menu', 'dashboard', 'list-tables', 'edit', 'revisions', 'media', 'themes', 'about', 'nav-menus', 'widgets', 'site-icon', 'l10n', 'wp-base-styles', 'wp-tooltip' ) );
16421642

16431643
$styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n', 'wp-base-styles', 'wp-tooltip' ) );
16441644
$styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'dashicons', 'buttons', 'forms', 'l10n', 'wp-base-styles' ) );

tests/phpunit/tests/general/wpGetTooltip.php

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ public function test_wp_get_tooltip_returns_empty_string_without_content() {
2828
public function test_wp_get_tooltip_returns_accessible_markup() {
2929
$tooltip = wp_get_tooltip( 'Helpful text.', array( 'id' => 'my-tip' ) );
3030

31-
// Toggle is a button that controls the popover and describes it.
32-
$this->assertStringContainsString( '<button type="button" class="wp-tooltip__toggle"', $tooltip );
33-
$this->assertStringContainsString( 'popovertarget="my-tip"', $tooltip );
31+
// Tooltip output should include a toggle button, but tooltips do not use a popover trigger.
32+
$this->assertStringContainsString( '<button', $tooltip );
33+
$this->assertStringContainsString( 'class="wp-tooltip__toggle"', $tooltip );
34+
$this->assertStringContainsString( 'type="button"', $tooltip );
35+
$this->assertStringNotContainsString( 'popovertarget="my-tip"', $tooltip );
3436

3537
// The bubble is a popover holding a text-only described element.
3638
$this->assertStringContainsString( '<span popover="hint" id="my-tip" class="wp-tooltip__bubble" role="tooltip">', $tooltip );
@@ -47,6 +49,7 @@ public function test_wp_get_tooltip_returns_accessible_markup() {
4749
)
4850
);
4951
// Ensure the toggle tip does contain a close button.
52+
$this->assertStringContainsString( 'popovertarget="my-tip"', $toggletip );
5053
$this->assertStringContainsString( 'class="wp-tooltip__close"', $toggletip );
5154
$this->assertStringContainsString( 'popovertargetaction="hide"', $toggletip );
5255
}
@@ -63,6 +66,50 @@ public function test_wp_get_tooltip_escapes_content() {
6366
$this->assertStringContainsString( '&lt;script&gt;', $html );
6467
}
6568

69+
/**
70+
* Tests that custom markup that does not contain valid control markup is ignored.
71+
*
72+
* @ticket 55343
73+
*/
74+
public function test_wp_get_tooltip_ignores_invalid_markup() {
75+
$html = wp_get_tooltip(
76+
'Helpful text.',
77+
array(
78+
'button' => '<div role="button" aria-expanded="false">Contains text</div>',
79+
)
80+
);
81+
82+
$this->assertStringNotContainsString( 'div role="button"', $html, 'String does not contain element from custom HTML.' );
83+
$this->assertStringContainsString( '<button', $html, 'String does contain a button element.' );
84+
}
85+
86+
/**
87+
* Tests that custom button markup is retained, and has required attributes.
88+
*
89+
* @ticket 55343
90+
*/
91+
public function test_wp_get_tooltip_has_custom_button_markup() {
92+
$html = wp_get_tooltip(
93+
'Helpful text.',
94+
array(
95+
'button' => '<button type="button" aria-expanded="false">Contains text</button>',
96+
)
97+
);
98+
99+
$this->assertStringContainsString( 'aria-expanded="false"', $html, 'String contains attribute not supported in function.' );
100+
$this->assertStringNotContainsString( 'dashicons', $html, 'String does not contain content of default button.' );
101+
102+
$html2 = wp_get_tooltip(
103+
'Helpful text.',
104+
array(
105+
'button' => '<a href="#">Contains text</a>',
106+
)
107+
);
108+
109+
$this->assertStringContainsString( '<a ', $html2, 'String contains anchor element.' );
110+
$this->assertStringNotContainsString( '<button', $html2, 'String does not contain button element.' );
111+
}
112+
66113
/**
67114
* Tests that the accessible labels are output and escaped in attributes.
68115
*
@@ -101,12 +148,16 @@ public function test_wp_get_tooltip_applies_icon_and_class() {
101148

102149
/**
103150
* Tests that a generated ID is used when none is supplied, and that the
104-
* describedby target matches the bubble ID.
151+
* popovertarget matches the bubble ID.
105152
*
106153
* @ticket 55343
107154
*/
108-
public function test_wp_get_tooltip_generates_unique_id() {
109-
$html = wp_get_tooltip( 'Helpful text.' );
155+
public function test_wp_get_toggletip_generates_unique_id() {
156+
$args = array(
157+
'label' => 'About this field',
158+
'close_label' => 'Dismiss',
159+
);
160+
$html = wp_get_toggletip( 'Helpful text.', $args );
110161

111162
$this->assertSame( 1, preg_match( '/id="(wp-tooltip-\d+)"/', $html, $matches ) );
112163

0 commit comments

Comments
 (0)