Changeset 3736912
- Timestamp:
- 10/09/2026 02:51:29 PM (2 weeks ago)
- Location:
- metro-tabs/trunk
- Files:
-
- 6 added
- 5 edited
-
block.json (modified) (1 diff)
-
blocks (added)
-
blocks/tab-group (added)
-
blocks/tab-group/block.json (added)
-
css/core-tabs.css (added)
-
css/metrotabs.css (added)
-
js/metrotabs-group.js (modified) (2 diffs)
-
js/metrotabs-item.js (modified) (3 diffs)
-
js/metrotabs-view.js (added)
-
metro-tabs.php (modified) (4 diffs)
-
readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
metro-tabs/trunk/block.json
r3481088 r3736912 7 7 "description": "One tab (heading + content) for use inside a Metro Tabs tab group.", 8 8 "keywords": ["tab", "tabs", "metro-tabs"], 9 "text Domain": "metro-tabs",9 "textdomain": "metro-tabs", 10 10 "apiVersion": 3, 11 "parent": ["getbutterfly/gb-tab-group"] 11 "parent": ["getbutterfly/gb-tab-group"], 12 "attributes": { 13 "title": { 14 "type": "string" 15 }, 16 "icon": { 17 "type": "string", 18 "default": "" 19 } 20 }, 21 "usesContext": ["getbutterfly/metrotabs"], 22 "supports": { 23 "html": false, 24 "reusable": false 25 } 12 26 } -
metro-tabs/trunk/js/metrotabs-group.js
r3481381 r3736912 1 (function (blocks, element, editor, i18n) { 2 var createElement = element.createElement; 3 var __ = i18n.__; 4 var useBlockProps = editor.useBlockProps; 5 var InnerBlocks = editor.InnerBlocks; 1 (function (blocks, element, editor, components, i18n) { 2 const { createElement: el, Fragment } = element; 3 const { __ } = i18n; 4 const { useBlockProps, InnerBlocks, InspectorControls } = editor; 5 const { PanelBody, SelectControl, ToggleControl, RangeControl } = components; 6 const { createBlock, cloneBlock } = blocks; 6 7 7 8 blocks.registerBlockType('getbutterfly/gb-tab-group', { 8 apiVersion: 3, 9 title: 'Metro Tabs: Tab Group', 10 icon: 'index-card', 11 category: 'widgets', 12 description: __('A group of tabs. Add "Metro Tabs: Tab Item" blocks inside.', 'metro-tabs'), 13 14 attributes: {}, 15 16 edit: function (props) { 17 var blockProps = useBlockProps({ 18 className: 'metrotabs-group', 9 edit({ attributes, setAttributes }) { 10 const blockProps = useBlockProps({ 11 className: `metrotabs-group${attributes.orientation === 'vertical' ? ' is-vertical' : ''}`, 19 12 }); 20 13 21 return createElement('div', blockProps, 22 createElement(InnerBlocks, { 23 allowedBlocks: ['getbutterfly/gb-tab-block'], 24 placeholder: __('Add Metro Tabs: Tab Item blocks here.', 'metro-tabs'), 25 template: [ 26 ['getbutterfly/gb-tab-block', { title: 'Tab 1' }], 27 ['getbutterfly/gb-tab-block', { title: 'Tab 2' }], 28 ], 29 }) 14 return el( 15 Fragment, 16 null, 17 el( 18 InspectorControls, 19 null, 20 el( 21 PanelBody, 22 { title: __('Tabs', 'metro-tabs') }, 23 el(SelectControl, { 24 __nextHasNoMarginBottom: true, 25 __next40pxDefaultSize: true, 26 label: __('Orientation', 'metro-tabs'), 27 value: attributes.orientation, 28 options: [ 29 { label: __('Horizontal', 'metro-tabs'), value: 'horizontal' }, 30 { label: __('Vertical', 'metro-tabs'), value: 'vertical' }, 31 ], 32 onChange: (orientation) => setAttributes({ orientation }), 33 }), 34 el(ToggleControl, { 35 __nextHasNoMarginBottom: true, 36 label: __('Accordion on small screens', 'metro-tabs'), 37 checked: attributes.accordionBreakpoint > 0, 38 onChange: (on) => setAttributes({ accordionBreakpoint: on ? 600 : 0 }), 39 }), 40 attributes.accordionBreakpoint > 0 && el(RangeControl, { 41 __nextHasNoMarginBottom: true, 42 __next40pxDefaultSize: true, 43 label: __('Switch to accordion below (px)', 'metro-tabs'), 44 value: attributes.accordionBreakpoint, 45 min: 320, 46 max: 1200, 47 step: 10, 48 onChange: (accordionBreakpoint) => setAttributes({ accordionBreakpoint }), 49 }), 50 el(SelectControl, { 51 __nextHasNoMarginBottom: true, 52 __next40pxDefaultSize: true, 53 label: __('Panel animation', 'metro-tabs'), 54 help: __('Turned off automatically for visitors who prefer reduced motion.', 'metro-tabs'), 55 value: attributes.animation, 56 options: [ 57 { label: __('None', 'metro-tabs'), value: 'none' }, 58 { label: __('Fade', 'metro-tabs'), value: 'fade' }, 59 { label: __('Slide', 'metro-tabs'), value: 'slide' }, 60 ], 61 onChange: (animation) => setAttributes({ animation }), 62 }) 63 ), 64 el( 65 PanelBody, 66 { title: __('Links', 'metro-tabs'), initialOpen: false }, 67 el(ToggleControl, { 68 __nextHasNoMarginBottom: true, 69 label: __('Update the address bar when a tab is opened', 'metro-tabs'), 70 help: __('Makes every tab shareable with a #link.', 'metro-tabs'), 71 checked: attributes.updateUrl, 72 onChange: (updateUrl) => setAttributes({ updateUrl }), 73 }), 74 el(ToggleControl, { 75 __nextHasNoMarginBottom: true, 76 label: __('Remember the last opened tab', 'metro-tabs'), 77 help: __('Stored in the visitor\'s browser for this page.', 'metro-tabs'), 78 checked: attributes.remember, 79 onChange: (remember) => setAttributes({ remember }), 80 }) 81 ) 82 ), 83 el( 84 'div', 85 blockProps, 86 el(InnerBlocks, { 87 allowedBlocks: ['getbutterfly/gb-tab-block'], 88 placeholder: __('Add Metro Tabs: Tab Item blocks here.', 'metro-tabs'), 89 template: [ 90 ['getbutterfly/gb-tab-block', { title: 'Tab 1' }], 91 ['getbutterfly/gb-tab-block', { title: 'Tab 2' }], 92 ], 93 }) 94 ) 30 95 ); 31 96 }, 32 97 33 save: function () { 34 var blockProps = useBlockProps.save({ 35 className: 'metrotabs-group', 36 }); 98 save() { 99 return el('div', useBlockProps.save({ className: 'metrotabs-group' }), el(InnerBlocks.Content)); 100 }, 37 101 38 return createElement('div', blockProps, 39 createElement(InnerBlocks.Content) 40 ); 102 transforms: { 103 to: [ 104 { 105 type: 'block', 106 blocks: ['core/tabs'], 107 transform: (attributes, innerBlocks) => createBlock('core/tabs', {}, [ 108 createBlock('core/tab-list'), 109 createBlock('core/tab-panels', {}, innerBlocks.map((item) => createBlock( 110 'core/tab-panel', 111 { label: item.attributes.title ?? '' }, 112 item.innerBlocks.map((block) => cloneBlock(block)) 113 ))), 114 ]), 115 }, 116 ], 117 from: [ 118 { 119 type: 'block', 120 blocks: ['core/tabs'], 121 transform: (attributes, innerBlocks) => { 122 const panels = innerBlocks.find((block) => block.name === 'core/tab-panels')?.innerBlocks ?? []; 123 124 return createBlock('getbutterfly/gb-tab-group', {}, panels.map((panel) => createBlock( 125 'getbutterfly/gb-tab-block', 126 { title: panel.attributes.label ?? '' }, 127 panel.innerBlocks.map((block) => cloneBlock(block)) 128 ))); 129 }, 130 }, 131 ], 41 132 }, 42 133 }); … … 45 136 window.wp.element, 46 137 window.wp.blockEditor, 138 window.wp.components, 47 139 window.wp.i18n 48 140 ); -
metro-tabs/trunk/js/metrotabs-item.js
r3481381 r3736912 10 10 11 11 blocks.registerBlockType('getbutterfly/gb-tab-block', { 12 apiVersion: 3,13 title: 'Metro Tabs: Tab Item',14 icon: 'welcome-widgets-menus',15 category: 'widgets',16 17 attributes: {18 title: {19 type: 'string',20 },21 },22 23 12 edit: function (props) { 24 13 var blockProps = useBlockProps(); … … 26 15 return createElement('div', blockProps, 27 16 [ 17 createElement(InspectorControls, { key: 'inspector' }, 18 createElement(components.PanelBody, { title: __('Tab', 'metro-tabs') }, 19 createElement(components.TextControl, { 20 __nextHasNoMarginBottom: true, 21 __next40pxDefaultSize: true, 22 label: __('Icon (Dashicon name)', 'metro-tabs'), 23 help: __('Optional, e.g. "star-filled" or "admin-home". Shown before the tab label.', 'metro-tabs'), 24 value: props.attributes.icon, 25 onChange: function (icon) { 26 props.setAttributes({ icon: icon.replace(/^dashicons-/, '').trim() }); 27 }, 28 }) 29 ) 30 ), 28 31 createElement(wp.blockEditor.RichText, { 32 key: 'title', 29 33 tagName: 'h3', 30 34 value: props.attributes.title, 31 class : 'gb-tab-item',35 className: 'gb-tab-item', 32 36 onChange: function (content) { 33 37 props.setAttributes({ title: content }); … … 36 40 }), 37 41 createElement('div', { 42 key: 'content', 38 43 className: 'gb-tab-content', 39 44 }, -
metro-tabs/trunk/metro-tabs.php
r3692098 r3736912 1 1 <?php 2 2 /** 3 * Plugin Name: Metro Tabs - Responsive Tabs Block3 * Plugin Name: Metro Tabs – Vertical, Responsive & Linkable Tabs Block 4 4 * Plugin URI: https://getbutterfly.com/wordpress-plugins/metro-tabs/ 5 * Description: Add responsive tab blocks to posts and pages. Group multiple tabs, add any blocks inside each tab. No jQuery, no dependencies. 6 * Version: 1.1.7 5 * Description: Tabs that go beyond Core: vertical tabs, accordion on mobile, shareable links, icons and style presets. Accessible, no jQuery. 6 * Version: 1.2.0 7 * Requires at least: 7.1 8 * Requires PHP: 8.0 7 9 * Author: Ciprian Popescu 8 10 * Author URI: https://getbutterfly.com/ … … 23 25 } 24 26 25 define( 'METRO_TABS_VERSION', '1. 1.7' );27 define( 'METRO_TABS_VERSION', '1.2.0' ); 26 28 define( 'METRO_TABS_PLUGIN_FILE', __FILE__ ); 27 29 define( 'METRO_TABS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); … … 29 31 30 32 /** 31 * Bootstrap the plugin by hooking script/style registration andblock registration into init.33 * Bootstrap the plugin by hooking block registration into init. 32 34 * 33 35 * @return void 34 36 */ 35 37 function getbutterfly_metrotabs_setup() { 36 add_action( 'init', 'getbutterfly_metrotabs_register_scripts' );37 38 add_action( 'init', 'getbutterfly_metrotabs_register_block' ); 38 39 } 39 40 40 41 /** 41 * Register and enqueue front-end styles and scripts. 42 * 43 * Only loads assets on non-admin pages. 42 * Register editor assets, the Tab Item and Tab Group block types, and the Core Tabs style pack. 44 43 * 45 44 * @return void 46 45 */ 47 function getbutterfly_metrotabs_register_scripts() {48 if ( ! is_admin() ) {49 wp_register_style( 'metrotabs-block-css', plugins_url( 'css/metrotabs-block.css', __FILE__ ), [], METRO_TABS_VERSION );50 wp_enqueue_style( 'metrotabs-block-css', plugins_url( 'css/metrotabs-block.css', __FILE__ ), [], METRO_TABS_VERSION );51 52 wp_register_script( 'metrotabs-block-js', plugins_url( 'js/metrotabs-block.js', __FILE__ ), [], METRO_TABS_VERSION, true );53 wp_enqueue_script( 'metrotabs-block-js', plugins_url( 'js/metrotabs-block.js', __FILE__ ), [], METRO_TABS_VERSION, true );54 }55 }56 57 /**58 * Register editor assets and the Tab Item and Tab Group block types.59 *60 * @return void61 */62 46 function getbutterfly_metrotabs_register_block() { 63 global $pagenow; 64 65 $dependencies = ( $pagenow === 'widgets.php' ) ? [ 'wp-edit-widgets', 'wp-blocks', 'wp-i18n', 'wp-element' ] : [ 'wp-block-editor', 'wp-blocks', 'wp-i18n', 'wp-element' ]; 66 47 $dependencies = [ 'wp-block-editor', 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-components' ]; 48 49 wp_register_style( 'metrotabs-block-css', plugins_url( 'css/metrotabs.css', __FILE__ ), [], METRO_TABS_VERSION ); 67 50 wp_register_style( 'metrotabs-block-editor-css', plugins_url( 'css/metrotabs-block-editor.css', __FILE__ ), [], METRO_TABS_VERSION ); 51 wp_register_script_module( 'metrotabs-view', plugins_url( 'js/metrotabs-view.js', __FILE__ ), [], METRO_TABS_VERSION ); 68 52 69 53 wp_register_script( 'getbutterfly-metrotabs-block', plugins_url( 'js/metrotabs-item.js', __FILE__ ), $dependencies, METRO_TABS_VERSION, false ); … … 73 57 METRO_TABS_PLUGIN_DIR . 'block.json', 74 58 [ 75 'editor_script' => 'getbutterfly-metrotabs-block', 76 'editor_style' => 'metrotabs-block-editor-css', 59 'editor_script' => 'getbutterfly-metrotabs-block', 60 'editor_style' => 'metrotabs-block-editor-css', 61 'render_callback' => 'getbutterfly_metrotabs_render_item', 77 62 ] 78 63 ); 79 64 80 65 register_block_type( 81 'getbutterfly/gb-tab-group',66 METRO_TABS_PLUGIN_DIR . 'blocks/tab-group/block.json', 82 67 [ 83 'apiVersion' => 3, 84 'editor_script' => 'getbutterfly-metrotabs-group', 85 'editor_style' => 'metrotabs-block-editor-css', 68 'editor_script' => 'getbutterfly-metrotabs-group', 69 'editor_style' => 'metrotabs-block-editor-css', 70 'style' => 'metrotabs-block-css', 71 'render_callback' => 'getbutterfly_metrotabs_render_group', 86 72 ] 87 73 ); 74 75 wp_register_style( 'metrotabs-core-tabs', plugins_url( 'css/core-tabs.css', __FILE__ ), [], METRO_TABS_VERSION ); 76 77 foreach ( [ 'pills' => __( 'Metro Pills', 'metro-tabs' ), 'boxed' => __( 'Metro Boxed', 'metro-tabs' ), 'segmented' => __( 'Metro Segmented', 'metro-tabs' ), 'underline' => __( 'Metro Underline', 'metro-tabs' ) ] as $name => $label ) { 78 register_block_style( 79 'core/tabs', 80 [ 81 'name' => 'metrotabs-' . $name, 82 'label' => $label, 83 'style_handle' => 'metrotabs-core-tabs', 84 ] 85 ); 86 } 87 } 88 89 /** 90 * Server-render a tab group as an accessible tablist with panels (and hidden accordion headings). 91 * 92 * @param array $attributes Block attributes. 93 * @param string $content Saved markup (unused; rebuilt from inner blocks). 94 * @param WP_Block $block Block instance. 95 * @return string 96 */ 97 function getbutterfly_metrotabs_render_group( $attributes, $content, $block ) { 98 static $group_index = 0; 99 100 // Matches the ids generated by versions before 2.0 so existing #links keep working. 101 $prefix = 'metrotabs-g' . $group_index++ . '-'; 102 $vertical = $attributes['orientation'] === 'vertical'; 103 $buttons = ''; 104 $panels = ''; 105 $used = []; 106 $items = getbutterfly_metrotabs_items( null, count( $block->inner_blocks ) ); 107 108 foreach ( $items as $index => [ $title, $icon, $inner ] ) { 109 $label = wp_strip_all_tags( $title ); 110 $slug = sanitize_title( $label ) ?: 'tab-' . ( $index + 1 ); 111 $slug = isset( $used[ $slug ] ) ? $slug . '-' . ( $index + 1 ) : $slug; 112 $id = $prefix . $slug; 113 $icon = sanitize_html_class( $icon ); 114 $first = $index === 0; 115 116 $used[ $slug ] = true; 117 118 if ( $icon !== '' ) { 119 wp_enqueue_style( 'dashicons' ); 120 $title = '<span class="dashicons dashicons-' . $icon . '" aria-hidden="true"></span>' . $title; 121 } 122 123 $buttons .= sprintf( 124 '<button type="button" role="tab" class="metrotabs-tab-trigger%s" id="%s-tab" aria-controls="%s" aria-selected="%s" tabindex="%s">%s</button>', 125 $first ? ' active' : '', 126 esc_attr( $id ), 127 esc_attr( $id ), 128 $first ? 'true' : 'false', 129 $first ? '0' : '-1', 130 wp_kses_post( $title ) 131 ); 132 133 $panels .= sprintf( 134 '<h3 class="metrotabs-accordion-heading"><button type="button" aria-expanded="%s" aria-controls="%s">%s</button></h3><div role="tabpanel" class="tab-pane" id="%s" aria-labelledby="%s-tab" tabindex="0"%s>%s</div>', 135 $first ? 'true' : 'false', 136 esc_attr( $id ), 137 wp_kses_post( $title ), 138 esc_attr( $id ), 139 esc_attr( $id ), 140 $first ? '' : ' hidden', 141 $inner 142 ); 143 } 144 145 if ( $buttons === '' ) { 146 return ''; 147 } 148 149 wp_enqueue_script_module( 'metrotabs-view' ); 150 151 $wrapper = get_block_wrapper_attributes( 152 [ 153 'class' => 'metrotabs-group' . ( $vertical ? ' is-vertical' : '' ), 154 'data-accordion' => (string) max( 0, (int) $attributes['accordionBreakpoint'] ), 155 'data-update-url' => $attributes['updateUrl'] ? '1' : '0', 156 'data-remember' => $attributes['remember'] ? '1' : '0', 157 'data-animation' => sanitize_key( $attributes['animation'] ), 158 ] 159 ); 160 161 return sprintf( 162 '<div %s><div class="metro-tabs-block"><div role="tablist" class="metrotabs-tablist" aria-orientation="%s">%s</div>%s</div></div>', 163 $wrapper, 164 $vertical ? 'vertical' : 'horizontal', 165 $buttons, 166 $panels 167 ); 168 } 169 170 /** 171 * Stack of rendered tab items. WordPress renders inner blocks before the parent's callback, 172 * so each group takes the last N items pushed (nested groups take theirs first). 173 * 174 * @param array|null $push Item to push: [ title, icon, inner HTML ]. 175 * @param int $take Number of items to pop. 176 * @return array 177 */ 178 function getbutterfly_metrotabs_items( $push = null, $take = 0 ) { 179 static $stack = []; 180 181 if ( $push !== null ) { 182 $stack[] = $push; 183 184 return []; 185 } 186 187 return $take > 0 ? array_splice( $stack, -$take ) : []; 188 } 189 190 /** 191 * Tab item render: inside a group it hands its content to the group; outside a group 192 * (content from before tab groups existed) it renders as a native disclosure. 193 * 194 * @param array $attributes Block attributes. 195 * @param string $content Saved markup with rendered inner blocks. 196 * @param WP_Block $block Block instance. 197 * @return string 198 */ 199 function getbutterfly_metrotabs_render_item( $attributes, $content, $block ) { 200 $title = (string) ( $attributes['title'] ?? '' ); 201 $start = strpos( $content, '<div class="gb-tab-content">' ); 202 $inner = $start === false ? '' : substr( $content, $start + strlen( '<div class="gb-tab-content">' ) ); 203 // Drop the closing </div></div> of the saved wrapper. 204 $inner = preg_replace( '~</div>\s*</div>\s*$~', '', $inner ); 205 206 if ( isset( $block->context['getbutterfly/metrotabs'] ) ) { 207 getbutterfly_metrotabs_items( [ $title, (string) ( $attributes['icon'] ?? '' ), $inner ] ); 208 209 return ''; 210 } 211 212 return '<details class="metrotabs-orphan"><summary>' . wp_kses_post( $title ) . '</summary>' . $inner . '</details>'; 88 213 } 89 214 -
metro-tabs/trunk/readme.txt
r3692098 r3736912 1 === Metro Tabs - Responsive Tabs Block ===1 === Metro Tabs – Vertical, Responsive & Linkable Tabs Block === 2 2 Contributors: butterflymedia 3 3 Donate link: https://buymeacoffee.com/wolffe 4 Tags: tab , tabs, gutenberg, blocks, responsive4 Tags: tabs, vertical tabs, accordion, tabs block, responsive 5 5 Plugin URI: https://getbutterfly.com/wordpress-plugins/metro-tabs/ 6 6 Requires PHP: 8.0 7 Requires at least: 6.08 Tested up to: 7.1 9 Stable tag: 1. 1.77 Requires at least: 7.1 8 Tested up to: 7.1.3 9 Stable tag: 1.2.0 10 10 License: GNU General Public License v3 or later 11 11 License URI: https://www.gnu.org/licenses/gpl-3.0.html 12 12 13 Tab blocks: multiple groups per page, any blocks in each tab. No jQuery, no dependencies.13 For site builders who need more than the core Tabs block: vertical tabs, accordion on mobile, shareable tab links, icons and style presets. 14 14 15 15 == Description == 16 16 17 Metro Tabs adds block-editor (Gutenberg) blocks for building tabbed content. You add a **Metro Tabs: Tab Group** block, then add one or more **Metro Tabs: Tab Item** blocks inside it. Each tab has a heading (the label visitors click) and a content area where you can add any blocks—paragraphs, images, lists, etc. On the front end, visitors see a simple tab bar and panes; clicking a tab switches the visible content without reloading the page. 17 WordPress 7.1 added a basic Tabs block. Metro Tabs uses the same accessible tabs pattern and adds what Core doesn't do: 18 18 19 = Features = 19 * **Vertical tabs** – tab list on the side, with Up/Down arrow keys. 20 * **Accordion on mobile** – below a width you choose, the tabs turn into an accordion. 21 * **Shareable links** – optionally update the address bar when a tab opens, so every tab has its own #link. Links work on page load and when the hash changes. 22 * **Remember the last tab** a visitor opened on a page. 23 * **Icons in tab labels** (Dashicons). 24 * **Style presets** – Metro (underline), Pills, Boxed and Segmented, plus Color, Typography and Spacing panels. 25 * **Fade or slide** panel animation, switched off for visitors who prefer reduced motion. 26 * **Style pack for core Tabs** – the same four presets for the core Tabs block. 27 * **No lock-in** – transform Metro Tabs to core Tabs and back. 28 * Tabs are rendered on the server, so there is no flash of unstyled content, and the small script only loads on pages with tabs. 20 29 21 * **Tab Group block** – Container for one set of tabs. You can use multiple Tab Group blocks on the same page for different tab sets. 22 * **Tab Item block** – A single tab: editable heading and a content area that supports any blocks (paragraphs, headings, images, etc.). 23 * **No JavaScript libraries** – Uses vanilla JavaScript only; no jQuery or jQuery UI. 24 * **Block API version 3** – Compatible with the current block editor (WordPress 6.3+ iframe editor). 25 * **Lightweight styling** – Discrete front-end styles (underline-style active tab); you can override with your theme or custom CSS. 30 Add a **Metro Tabs** block, then edit the **Tab Item** blocks inside it. Each tab has a heading (the label visitors click) and a content area that takes any blocks. 26 31 27 32 = How to use = 28 33 29 1. In the block editor, add a **Metro Tabs : Tab Group** block (search for “Metro Tabs” or “Tab Group”).30 2. Inside the group, you’ll see placeholder Tab Items (e.g. “Tab 1”, “Tab 2”). Click each **Metro Tabs: Tab Item** block and:31 * Edit the **tab heading** (the text shown on the tab) .34 1. In the block editor, add a **Metro Tabs** block (search for “Metro Tabs” or “tabs”). 35 2. Inside it, you’ll see placeholder Tab Items (e.g. “Tab 1”, “Tab 2”). Click each **Metro Tabs: Tab Item** block and: 36 * Edit the **tab heading** (the text shown on the tab) and, optionally, pick an icon in the sidebar. 32 37 * Add any blocks in the **tab content** area (paragraphs, images, etc.). 33 3. Add or remove Tab Item blocks as needed. You can add more Tab Groups elsewhere on the page for separate tab sets. 34 4. Publish or update. On the front end, the tab bar and panes are built automatically; clicking a tab switches the visible pane. 35 36 No settings or configuration are required. The plugin enqueues its script and styles on the front end when the page contains tab blocks. 38 3. Select the Metro Tabs block to choose the orientation, accordion breakpoint, animation, links and style. 39 4. Publish or update. You can use several Metro Tabs blocks on the same page. 37 40 38 41 Explore more [WordPress Plugins](https://getbutterfly.com/wordpress-plugins/). … … 40 43 = Compatibility = 41 44 42 * Requires WordPress 6.0 or higher (block editor).45 * Requires WordPress 7.1 or higher. 43 46 * Requires PHP 8.0 or higher. 47 48 ### From the same author 49 50 * [Active Contacts - WordPress CRM & Follow-up Plugin](https://getbutterfly.com/wordpress-plugins/active-contacts/) 51 * [LazyClone - Copy a WordPress Site Without FTP](https://getbutterfly.com/wordpress-plugins/lazyclone/) 52 * [Lighthouse - WordPress Performance & Speed Optimization Plugin](https://getbutterfly.com/wordpress-plugins/lighthouse/) 53 * [Active Analytics - Privacy-Friendly WordPress Analytics Plugin](https://getbutterfly.com/wordpress-plugins/active-analytics/) 54 * [ImagePress - WordPress Image Gallery & Community Photo Plugin](https://getbutterfly.com/wordpress-plugins/imagepress/) 55 * [eCards - WordPress eCard Plugin with Email Designer](https://getbutterfly.com/wordpress-plugins/wordpress-ecards-plugin/) 56 * [Repeater for Gravity Forms - Repeater Field Add-on](https://getbutterfly.com/wordpress-plugins/gravity-forms-repeater-plugin/) 57 * [Fixtures & Results - WordPress Sports League & GAA Club Plugin](https://getbutterfly.com/wordpress-plugins/fixtures-and-results/) 58 * [WP Google Consent Platform (GCP)](https://getbutterfly.com/wordpress-plugins/wp-gcp-a-wordpress-plugin-for-google-consent-mode-v2/) 44 59 45 60 == Screenshots == … … 53 68 54 69 == Changelog == 70 71 = 1.2.0 = 72 * FEATURE: Vertical tabs (Up/Down arrow keys, `aria-orientation="vertical"`) 73 * FEATURE: Accordion below a chosen screen width 74 * FEATURE: Optional address bar update on tab change, and remember the last opened tab 75 * FEATURE: Dashicons in tab labels 76 * FEATURE: Style presets (Metro, Pills, Boxed, Segmented), Color, Typography, Spacing and anchor support 77 * FEATURE: Fade/slide panel animation (respects reduced motion) 78 * FEATURE: Style pack for the core Tabs block, and transforms between Metro Tabs and core Tabs 79 * PERFORMANCE: Tabs are rendered on the server (no layout shift); the script is a small ES module loaded only on pages with tabs; the stylesheet only loads with the block 80 * UPDATE: The tab list is now a `div` of buttons instead of `ul`/`li`. Existing tab links (#metrotabs-g0-...) keep working. Update any custom CSS that targeted `.metro-tabs-block ul li` 81 * UPDATE: Tab items saved outside a tab group (very old content) render as a native disclosure 82 * UPDATE: Requires WordPress 7.1 55 83 56 84 = 1.1.7 = … … 88 116 = 1.1.0 = 89 117 * First release 118
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)