Plugin Directory

Changeset 3736912


Ignore:
Timestamp:
10/09/2026 02:51:29 PM (2 weeks ago)
Author:
butterflymedia
Message:

Add vertical tabs, accordions, Dashicons and UI tweaks

Location:
metro-tabs/trunk
Files:
6 added
5 edited

Legend:

Unmodified
Added
Removed
  • metro-tabs/trunk/block.json

    r3481088 r3736912  
    77    "description": "One tab (heading + content) for use inside a Metro Tabs tab group.",
    88    "keywords": ["tab", "tabs", "metro-tabs"],
    9     "textDomain": "metro-tabs",
     9    "textdomain": "metro-tabs",
    1010    "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    }
    1226}
  • 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;
    67
    78    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' : ''}`,
    1912            });
    2013
    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                )
    3095            );
    3196        },
    3297
    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        },
    37101
    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            ],
    41132        },
    42133    });
    … …  
    45136    window.wp.element,
    46137    window.wp.blockEditor,
     138    window.wp.components,
    47139    window.wp.i18n
    48140);
  • metro-tabs/trunk/js/metrotabs-item.js

    r3481381 r3736912  
    1010
    1111    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 
    2312        edit: function (props) {
    2413            var blockProps = useBlockProps();
    … …  
    2615            return createElement('div', blockProps,
    2716                [
     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                    ),
    2831                    createElement(wp.blockEditor.RichText, {
     32                        key: 'title',
    2933                        tagName: 'h3',
    3034                        value: props.attributes.title,
    31                         class: 'gb-tab-item',
     35                        className: 'gb-tab-item',
    3236                        onChange: function (content) {
    3337                            props.setAttributes({ title: content });
    … …  
    3640                    }),
    3741                    createElement('div', {
     42                        key: 'content',
    3843                        className: 'gb-tab-content',
    3944                    },
  • metro-tabs/trunk/metro-tabs.php

    r3692098 r3736912  
    11<?php
    22/**
    3  * Plugin Name: Metro Tabs - Responsive Tabs Block
     3 * Plugin Name: Metro Tabs – Vertical, Responsive & Linkable Tabs Block
    44 * 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
    79 * Author: Ciprian Popescu
    810 * Author URI: https://getbutterfly.com/
    … …  
    2325}
    2426
    25 define( 'METRO_TABS_VERSION', '1.1.7' );
     27define( 'METRO_TABS_VERSION', '1.2.0' );
    2628define( 'METRO_TABS_PLUGIN_FILE', __FILE__ );
    2729define( 'METRO_TABS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
    … …  
    2931
    3032/**
    31  * Bootstrap the plugin by hooking script/style registration and block registration into init.
     33 * Bootstrap the plugin by hooking block registration into init.
    3234 *
    3335 * @return void
    3436 */
    3537function getbutterfly_metrotabs_setup() {
    36     add_action( 'init', 'getbutterfly_metrotabs_register_scripts' );
    3738    add_action( 'init', 'getbutterfly_metrotabs_register_block' );
    3839}
    3940
    4041/**
    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.
    4443 *
    4544 * @return void
    4645 */
    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 void
    61  */
    6246function 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 );
    6750    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 );
    6852
    6953    wp_register_script( 'getbutterfly-metrotabs-block', plugins_url( 'js/metrotabs-item.js', __FILE__ ), $dependencies, METRO_TABS_VERSION, false );
    … …  
    7357        METRO_TABS_PLUGIN_DIR . 'block.json',
    7458        [
    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',
    7762        ]
    7863    );
    7964
    8065    register_block_type(
    81         'getbutterfly/gb-tab-group',
     66        METRO_TABS_PLUGIN_DIR . 'blocks/tab-group/block.json',
    8267        [
    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',
    8672        ]
    8773    );
     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 */
     97function 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 */
     178function 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 */
     199function 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>';
    88213}
    89214
  • metro-tabs/trunk/readme.txt

    r3692098 r3736912  
    1 === Metro Tabs - Responsive Tabs Block ===
     1=== Metro Tabs – Vertical, Responsive & Linkable Tabs Block ===
    22Contributors: butterflymedia
    33Donate link: https://buymeacoffee.com/wolffe
    4 Tags: tab, tabs, gutenberg, blocks, responsive
     4Tags: tabs, vertical tabs, accordion, tabs block, responsive
    55Plugin URI: https://getbutterfly.com/wordpress-plugins/metro-tabs/
    66Requires PHP: 8.0
    7 Requires at least: 6.0
    8 Tested up to: 7.1
    9 Stable tag: 1.1.7
     7Requires at least: 7.1
     8Tested up to: 7.1.3
     9Stable tag: 1.2.0
    1010License: GNU General Public License v3 or later
    1111License URI: https://www.gnu.org/licenses/gpl-3.0.html
    1212
    13 Tab blocks: multiple groups per page, any blocks in each tab. No jQuery, no dependencies.
     13For site builders who need more than the core Tabs block: vertical tabs, accordion on mobile, shareable tab links, icons and style presets.
    1414
    1515== Description ==
    1616
    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.
     17WordPress 7.1 added a basic Tabs block. Metro Tabs uses the same accessible tabs pattern and adds what Core doesn't do:
    1818
    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.
    2029
    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.
     30Add 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.
    2631
    2732= How to use =
    2833
    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).
     341. In the block editor, add a **Metro Tabs** block (search for “Metro Tabs” or “tabs”).
     352. 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.
    3237   * 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.
     383. Select the Metro Tabs block to choose the orientation, accordion breakpoint, animation, links and style.
     394. Publish or update. You can use several Metro Tabs blocks on the same page.
    3740
    3841Explore more [WordPress Plugins](https://getbutterfly.com/wordpress-plugins/).
    … …  
    4043= Compatibility =
    4144
    42 * Requires WordPress 6.0 or higher (block editor).
     45* Requires WordPress 7.1 or higher.
    4346* 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/)
    4459
    4560== Screenshots ==
    … …  
    5368
    5469== 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
    5583
    5684= 1.1.7 =
    … …  
    88116= 1.1.0 =
    89117* First release
     118
Note: See TracChangeset for help on using the changeset viewer.