Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/tests-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ jobs:
matrix:
include:
- php: '8.1'
core: 'WordPress/WordPress#6.2'
core: 'WordPress/WordPress#6.4'
# null = latest official WordPress release (wp-env default).
- php: '8.3'
core: null
steps:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/tests-php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ jobs:
fail-fast: false
matrix:
php: ['8.1', '8.3']
# null = latest official WordPress release (wp-env default).
core: [null]
include:
- php: '8.1'
core: 'WordPress/WordPress#6.2'
core: 'WordPress/WordPress#6.4'
steps:
- name: Checkout
uses: actions/checkout@v4
Expand Down
20 changes: 13 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ An accessible tabs block for WordPress Gutenberg editor that follows ARIA best p

## Requirements

- WordPress 6.2 or higher
- WordPress 6.4 or higher
- PHP 8.1 or higher
- Gutenberg editor enabled

Expand Down Expand Up @@ -54,17 +54,23 @@ By default, the block comes with 3 tabs. Each tab contains a panel where you can

1. Select a tab item
2. In the block toolbar, click the "Icon" button
3. Choose an icon from the available options (native WordPress `core/icon` block)
3. Choose an icon from a registered icon block

To keep supporting Blockparty Icons / BeAPI Icon Block instead of (or in addition to) `core/icon`, use the `blockparty_tabs_allowed_icon_blocks` filter:
By default the plugin allows, in order:

1. `core/icon` (WordPress 7.0+)
2. `blockparty/icon`
3. `beapi/icon-block`

Only registered blocks are kept, so on WordPress 6.4–6.9 icons work when Blockparty Icons or BeAPI Icon Block is active. On WordPress 7.0+, `core/icon` is preferred when present.

Customize the list with the `blockparty_tabs_allowed_icon_blocks` filter:

```php
add_filter(
'blockparty_tabs_allowed_icon_blocks',
static function ( array $blocks ): array {
$blocks[] = 'blockparty/icon';
$blocks[] = 'beapi/icon-block';
return $blocks;
static function (): array {
return [ 'core/icon' ];
}
);
```
Expand Down
31 changes: 19 additions & 12 deletions blockparty-tabs.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/**
* Plugin Name: Blockparty Tabs
* Description: Accessible Tabs block for WordPress gutenberg.
* Requires at least: 6.2
* Requires at least: 6.4
* Requires PHP: 8.1
* Version: 1.1.5
* Author: Be API Technical team
Expand Down Expand Up @@ -32,9 +32,17 @@ function init(): void {
add_action( 'init', __NAMESPACE__ . '\\init' );

/**
* Default icon block used inside tab nav items.
* Default icon blocks allowed inside tab nav items.
*
* `core/icon` ships in WordPress 7.0+. Legacy Blockparty / BeAPI icon blocks
* remain in the default list so icons keep working on the required 6.4+ range
* whenever those plugins are active. The editor keeps only registered names.
*/
const BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK = 'core/icon';
const BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS = [
'core/icon',
'blockparty/icon',
'beapi/icon-block',
];

/**
* Returns the icon block names allowed inside tab nav items.
Expand All @@ -45,15 +53,14 @@ function get_allowed_icon_blocks(): array {
/**
* Filters the icon block types allowed inside tab nav items.
*
* By default only `core/icon` is allowed. To keep supporting
* Blockparty Icons / BeAPI Icon Block as before:
* Defaults prefer `core/icon` (WordPress 7.0+) and include
* `blockparty/icon` / `beapi/icon-block` for older installs. Example —
* allow only the native icon block:
*
* add_filter(
* 'blockparty_tabs_allowed_icon_blocks',
* static function ( array $blocks ): array {
* $blocks[] = 'blockparty/icon';
* $blocks[] = 'beapi/icon-block';
* return $blocks;
* static function (): array {
* return [ 'core/icon' ];
* }
* );
*
Expand All @@ -64,11 +71,11 @@ function get_allowed_icon_blocks(): array {
*/
$blocks = apply_filters(
'blockparty_tabs_allowed_icon_blocks',
[ BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK ]
BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS
);

if ( ! is_array( $blocks ) ) {
return [ BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK ];
return BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS;
}

$sanitized = [];
Expand All @@ -87,7 +94,7 @@ function get_allowed_icon_blocks(): array {

$sanitized = array_values( array_unique( $sanitized ) );

return [] === $sanitized ? [ BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK ] : $sanitized;
return [] === $sanitized ? BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS : $sanitized;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"phpunit/phpunit": "9.6.37",
"roave/security-advisories": "dev-latest",
"wp-coding-standards/wpcs": "^3.0",
"wp-phpunit/wp-phpunit": "6.8.9",
"wp-phpunit/wp-phpunit": "7.1.1",
"yoast/phpunit-polyfills": "4.0.0"
},
"scripts": {
Expand Down
8 changes: 5 additions & 3 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
=== Blockparty Tabs ===
Contributors: Be API Technical team
Tags: block
Tested up to: 6.0
Stable tag: 1.1.5
Tags: block, tabs, accessibility
Requires at least: 6.4
Requires PHP: 8.1
Tested up to: 7.1
Stable tag: 2.0.0
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Expand Down
15 changes: 13 additions & 2 deletions src/blockparty-tabs-nav-item/getAllowedIconBlocks.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { getBlockType } from '@wordpress/blocks';

const BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK = 'core/icon';
/**
* Default icon blocks allowed inside tab nav items.
*
* `core/icon` ships in WordPress 7.0+. Legacy Blockparty / BeAPI icon blocks
* remain so icons keep working on WordPress 6.4–6.9 when those plugins are
* active. Only registered names are kept by getRegisteredIconBlocks().
*/
export const BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS = [
'core/icon',
'blockparty/icon',
'beapi/icon-block',
];

/**
* Legacy Blockparty / BeAPI icon blocks expect width + maxIcons.
Expand Down Expand Up @@ -33,7 +44,7 @@ export const getRegisteredIconBlocks = () => {
const candidates =
Array.isArray( fromPhp ) && fromPhp.length > 0
? fromPhp
: [ BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK ];
: BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS;

return candidates.filter(
( blockName ) => typeof getBlockType( blockName ) !== 'undefined'
Expand Down
31 changes: 28 additions & 3 deletions tests/js/getAllowedIconBlocks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Internal dependencies
*/
import {
BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS,
getIconTemplateAttributes,
getRegisteredIconBlocks,
} from '../../src/blockparty-tabs-nav-item/getAllowedIconBlocks';
Expand Down Expand Up @@ -41,12 +42,30 @@ describe( 'getRegisteredIconBlocks', () => {
delete window.blockpartyTabsSettings;
} );

it( 'defaults to core/icon when settings are missing', () => {
it( 'defaults to registered candidates from the shared default list', () => {
getBlockType.mockImplementation( ( name ) =>
name === 'core/icon' ? { name } : undefined
name === 'blockparty/icon' ? { name } : undefined
);

expect( getRegisteredIconBlocks() ).toEqual( [ 'core/icon' ] );
expect( BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS ).toEqual( [
'core/icon',
'blockparty/icon',
'beapi/icon-block',
] );
expect( getRegisteredIconBlocks() ).toEqual( [ 'blockparty/icon' ] );
} );

it( 'prefers core/icon when it is registered among defaults', () => {
getBlockType.mockImplementation( ( name ) =>
[ 'core/icon', 'blockparty/icon' ].includes( name )
? { name }
: undefined
);

expect( getRegisteredIconBlocks() ).toEqual( [
'core/icon',
'blockparty/icon',
] );
} );

it( 'keeps only registered blocks from PHP settings', () => {
Expand Down Expand Up @@ -77,4 +96,10 @@ describe( 'getRegisteredIconBlocks', () => {

expect( getRegisteredIconBlocks() ).toEqual( [] );
} );

it( 'returns an empty list on WordPress without core/icon or legacy plugins', () => {
getBlockType.mockReturnValue( undefined );

expect( getRegisteredIconBlocks() ).toEqual( [] );
} );
} );
39 changes: 32 additions & 7 deletions tests/php/AllowedIconBlocksTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use WP_UnitTestCase;
use function Blockparty\Tabs\get_allowed_icon_blocks;
use const Blockparty\Tabs\BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK;
use const Blockparty\Tabs\BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS;

/**
* @covers ::Blockparty\Tabs\get_allowed_icon_blocks
Expand All @@ -27,9 +27,34 @@ public function tearDown(): void {
/**
* @return void
*/
public function test_defaults_to_core_icon(): void {
public function test_defaults_include_core_and_legacy_icon_blocks(): void {
$this->assertSame(
[ BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK ],
BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS,
get_allowed_icon_blocks()
);
$this->assertSame(
[
'core/icon',
'blockparty/icon',
'beapi/icon-block',
],
get_allowed_icon_blocks()
);
}

/**
* @return void
*/
public function test_filter_can_replace_icon_blocks(): void {
add_filter(
'blockparty_tabs_allowed_icon_blocks',
static function (): array {
return [ 'core/icon' ];
}
);

$this->assertSame(
[ 'core/icon' ],
get_allowed_icon_blocks()
);
}
Expand All @@ -41,8 +66,7 @@ public function test_filter_can_append_icon_blocks(): void {
add_filter(
'blockparty_tabs_allowed_icon_blocks',
static function ( array $blocks ): array {
$blocks[] = 'blockparty/icon';
$blocks[] = 'beapi/icon-block';
$blocks[] = 'my-plugin/custom-icon';
return $blocks;
}
);
Expand All @@ -52,6 +76,7 @@ static function ( array $blocks ): array {
'core/icon',
'blockparty/icon',
'beapi/icon-block',
'my-plugin/custom-icon',
],
get_allowed_icon_blocks()
);
Expand Down Expand Up @@ -97,7 +122,7 @@ static function () {
);

$this->assertSame(
[ BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK ],
BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS,
get_allowed_icon_blocks()
);
}
Expand All @@ -114,7 +139,7 @@ static function (): array {
);

$this->assertSame(
[ BLOCKPARTY_TABS_DEFAULT_ICON_BLOCK ],
BLOCKPARTY_TABS_DEFAULT_ICON_BLOCKS,
get_allowed_icon_blocks()
);
}
Expand Down
5 changes: 2 additions & 3 deletions tests/playwright/specs/editor-tabs.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import { test, expect } from '../utils/fixtures';
/**
* Resolve the block editor content root.
*
* WordPress 6.3+ uses an iframed canvas (`editor-canvas`). Older versions render
* blocks in the parent document. `FrameLocator.or()` is unreliable when the
* iframe is absent, so detect the canvas mode explicitly.
* WordPress 6.4+ uses an iframed canvas (`editor-canvas`). Detect the canvas
* mode explicitly: `FrameLocator.or()` is unreliable when the iframe is absent.
*
* @param {import('@playwright/test').Page} page
*/
Expand Down
2 changes: 1 addition & 1 deletion webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
/**
* Polyfill for the `react-jsx-runtime` script handle added in WordPress 6.6.
* Modern @wordpress/scripts builds declare this dependency; without it, editor
* scripts never load on WordPress 6.2–6.5 and blocks stay unregistered.
* scripts never load on WordPress 6.4–6.5 and blocks stay unregistered.
*
* Compiled after the main blocks config (`dependencies`) so `output.clean` from
* `@wordpress/scripts` cannot delete the polyfill asset in a parallel race.
Expand Down
Loading