| @@ -7,68 +7,64 @@ | ||
| 7 | 7 | |
| 8 | 8 | /** |
| 9 | 9 | * Render callback for core/tab-list. |
| 10 | 10 | * |
| 11 | - * Re-renders each tab inner block with per-item context (index, id, | |
| 12 | - * label) injected from the tabs-list, so the tab render callback | |
| 13 | - * can add the correct IAPI directives for each button. | |
| 11 | + * Injects IAPI directives into the saved button HTML. The buttons already | |
| 12 | + * carry color/border/padding styles from save.jsx; this callback adds | |
| 13 | + * tab-specific attributes (id, aria-controls, context) and interactivity | |
| 14 | + * directives using data from the tabs-list context. | |
| 14 | 15 | * |
| 15 | - * @since 7.0.0 | |
| 16 | + * @since 7.1.0 | |
| 16 | 17 | * |
| 17 | 18 | * @param array $attributes Block attributes. |
| 18 | - * @param string $content Block content (rendered inner blocks from save.js). | |
| 19 | + * @param string $content Block content (rendered buttons from save.jsx). | |
| 19 | 20 | * @param \WP_Block $block WP_Block instance. |
| 20 | 21 | * |
| 21 | 22 | * @return string Updated HTML. |
| 22 | 23 | */ |
| 23 | 24 | function gutenberg_block_core_tab_list_render_callback( array $attributes, string $content, \WP_Block $block ): string { |
| 24 | - $tabs_list = $block->context['core/tabs-list'] ?? array(); | |
| 25 | + $tabs_list = $block->context['core/tabs-list'] ?? array(); | |
| 26 | + $aria_label = empty( $attributes['ariaLabel'] ) ? __( 'Tabbed content' ) : wp_strip_all_tags( $attributes['ariaLabel'] ); | |
| 25 | 27 | |
| 28 | + $tag_processor = new WP_HTML_Tag_Processor( $content ); | |
| 29 | + if ( $tag_processor->next_tag( array( 'class_name' => 'wp-block-tab-list' ) ) ) { | |
| 30 | + $tag_processor->set_attribute( 'aria-label', $aria_label ); | |
| 31 | + } | |
| 32 | + | |
| 26 | 33 | if ( empty( $tabs_list ) ) { |
| 27 | - return $content; | |
| 34 | + return $tag_processor->get_updated_html(); | |
| 28 | 35 | } |
| 29 | 36 | |
| 30 | - // Re-render each tab with per-item context (index, id, label). | |
| 31 | - // Match by position so items align with their corresponding tabs. | |
| 32 | - $buttons_html = ''; | |
| 33 | - $tab_position = 0; | |
| 37 | + $tab_index = 0; | |
| 34 | 38 | |
| 35 | - foreach ( $block->parsed_block['innerBlocks'] ?? array() as $parsed_tab ) { | |
| 36 | - if ( 'core/tab' !== ( $parsed_tab['blockName'] ?? '' ) ) { | |
| 37 | - continue; | |
| 38 | - } | |
| 39 | + while ( $tag_processor->next_tag( 'button' ) ) { | |
| 40 | + $tab_id = $tabs_list[ $tab_index ] ?? null; | |
| 39 | 41 | |
| 40 | - $tab = $tabs_list[ $tab_position ] ?? null; | |
| 41 | - $tab_index = $tab_position; | |
| 42 | - ++$tab_position; | |
| 43 | - | |
| 44 | - // Skip tabs with no matching tab panel. | |
| 45 | - if ( null === $tab ) { | |
| 46 | - continue; | |
| 42 | + if ( null === $tab_id ) { | |
| 43 | + break; | |
| 47 | 44 | } |
| 48 | 45 | |
| 49 | - $item_context = array_merge( | |
| 50 | - $block->context, | |
| 51 | - array( | |
| 52 | - 'core/tab-index' => $tab_index, | |
| 53 | - 'core/tab-id' => $tab['id'] ?? '', | |
| 54 | - 'core/tab-label' => $tab['label'] ?? '', | |
| 55 | - ) | |
| 46 | + $tag_processor->set_attribute( 'id', 'tab__' . $tab_id ); | |
| 47 | + $tag_processor->set_attribute( 'aria-controls', $tab_id ); | |
| 48 | + $tag_processor->set_attribute( 'data-wp-on--click', 'actions.handleTabClick' ); | |
| 49 | + $tag_processor->set_attribute( 'data-wp-on--keydown', 'actions.handleTabKeyDown' ); | |
| 50 | + $tag_processor->set_attribute( 'data-wp-bind--aria-selected', 'state.isActiveTab' ); | |
| 51 | + $tag_processor->set_attribute( 'data-wp-bind--tabindex', 'state.tabIndexAttribute' ); | |
| 52 | + $tag_processor->set_attribute( | |
| 53 | + 'data-wp-context', | |
| 54 | + wp_json_encode( array( 'tabIndex' => $tab_index ) ) | |
| 56 | 55 | ); |
| 57 | 56 | |
| 58 | - $tab_block = new WP_Block( $parsed_tab, $item_context ); | |
| 59 | - $buttons_html .= $tab_block->render(); | |
| 57 | + ++$tab_index; | |
| 60 | 58 | } |
| 61 | 59 | |
| 62 | - // Rebuild the wrapper using get_block_wrapper_attributes(). | |
| 63 | - $wrapper_attributes = get_block_wrapper_attributes( array( 'role' => 'tablist' ) ); | |
| 64 | - return sprintf( '<div %s>%s</div>', $wrapper_attributes, $buttons_html ); | |
| 60 | + return $tag_processor->get_updated_html(); | |
| 65 | 61 | } |
| 66 | 62 | |
| 67 | 63 | /** |
| 68 | 64 | * Registers the `core/tab-list` block on the server. |
| 69 | 65 | * |
| 70 | - * @since 7.0.0 | |
| 66 | + * @since 7.1.0 | |
| 71 | 67 | */ |
| 72 | 68 | function gutenberg_register_block_core_tab_list() { |
| 73 | 69 | register_block_type_from_metadata( |
| 74 | 70 | __DIR__ . '/tab-list', |