Skip to content

Commit 9715418

Browse files
committed
Block API: Add block visibility control support and UI
1 parent 58a5abc commit 9715418

File tree

20 files changed

+279
-5
lines changed

20 files changed

+279
-5
lines changed

docs/reference-guides/block-api/block-supports.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,34 @@ attributes: {
174174
}
175175
```
176176

177+
## blockVisibility
178+
179+
_**Note:** Since WordPress 6.9._
180+
181+
- Type: `boolean`
182+
- Default value: `true`
183+
184+
By default, a block can be hidden within the editor from the block "Options" dropdown or the block toolbar. To disable this behavior for a block, set `blockVisibility` to `false`.
185+
186+
```js
187+
supports: {
188+
// Don't allow the block to be hidden via the editor UI.
189+
blockVisibility: false
190+
}
191+
```
192+
193+
When a block is hidden, the state is stored in the block's `metadata` attribute:
194+
195+
```js
196+
attributes: {
197+
metadata: {
198+
blockVisibility: false
199+
}
200+
}
201+
```
202+
203+
This only affects visibility in the frontend.
204+
177205
## className
178206

179207
- Type: `boolean`

docs/reference-guides/core-blocks.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Reuse this design across your site. ([Source](https://github.com/WordPress/guten
4141

4242
- **Name:** core/block
4343
- **Category:** reusable
44-
- **Supports:** interactivity (clientNavigation), ~~customClassName~~, ~~html~~, ~~inserter~~, ~~renaming~~
44+
- **Supports:** interactivity (clientNavigation), ~~blockVisibility~~, ~~customClassName~~, ~~html~~, ~~inserter~~, ~~renaming~~
4545
- **Attributes:** content, ref
4646

4747
## Button
@@ -540,7 +540,7 @@ Show a block pattern. ([Source](https://github.com/WordPress/gutenberg/tree/trun
540540

541541
- **Name:** core/pattern
542542
- **Category:** theme
543-
- **Supports:** interactivity (clientNavigation), ~~html~~, ~~inserter~~, ~~renaming~~
543+
- **Supports:** interactivity (clientNavigation), ~~blockVisibility~~, ~~html~~, ~~inserter~~, ~~renaming~~
544544
- **Attributes:** slug
545545

546546
## Author
@@ -930,7 +930,7 @@ Edit the different global regions of your site, like the header, footer, sidebar
930930

931931
- **Name:** core/template-part
932932
- **Category:** theme
933-
- **Supports:** align, interactivity (clientNavigation), ~~html~~, ~~renaming~~, ~~reusable~~
933+
- **Supports:** align, interactivity (clientNavigation), ~~blockVisibility~~, ~~html~~, ~~renaming~~, ~~reusable~~
934934
- **Attributes:** area, slug, tagName, theme
935935

936936
## Term Description
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* Block visibility block support flag.
4+
*
5+
* @package gutenberg
6+
*/
7+
8+
/**
9+
* Render nothing if the block is hidden.
10+
*
11+
* @param string $block_content The block content.
12+
* @param array $block The block.
13+
*
14+
* @return string The block content.
15+
*/
16+
function gutenberg_render_block_visibility_support( $block_content, $block ) {
17+
if ( isset( $block['attrs']['metadata']['blockVisibility'] ) && false === $block['attrs']['metadata']['blockVisibility'] ) {
18+
return '';
19+
}
20+
21+
return $block_content;
22+
}
23+
24+
if ( function_exists( 'wp_render_block_visibility_support' ) ) {
25+
remove_filter( 'render_block', 'wp_render_block_visibility_support' );
26+
}
27+
add_filter( 'render_block', 'gutenberg_render_block_visibility_support', 10, 2 );

lib/load.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ function gutenberg_is_experiment_enabled( $name ) {
152152
require __DIR__ . '/block-supports/background.php';
153153
require __DIR__ . '/block-supports/block-style-variations.php';
154154
require __DIR__ . '/block-supports/aria-label.php';
155+
require __DIR__ . '/block-supports/block-visibility.php';
155156

156157
// Data views.
157158
require_once __DIR__ . '/experimental/data-views.php';

packages/block-editor/src/components/block-list/block.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,12 @@ function BlockListBlockProvider( props ) {
705705
originalBlockClientId: isInvalid
706706
? blocksWithSameName[ 0 ]
707707
: false,
708+
isHidden:
709+
hasBlockSupport(
710+
getBlockName( clientId ),
711+
'blockVisibility',
712+
true
713+
) && attributes?.metadata?.blockVisibility === false,
708714
};
709715
},
710716
[ clientId, rootClientId ]
@@ -747,6 +753,7 @@ function BlockListBlockProvider( props ) {
747753
className,
748754
defaultClassName,
749755
originalBlockClientId,
756+
isHidden,
750757
} = selectedProps;
751758

752759
// Users of the editor.BlockListBlock filter used to be able to
@@ -795,6 +802,7 @@ function BlockListBlockProvider( props ) {
795802
originalBlockClientId,
796803
themeSupportsLayout,
797804
canMove,
805+
isHidden,
798806
};
799807

800808
// Here we separate between the props passed to BlockListBlock and any other

packages/block-editor/src/components/block-list/content.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ _::-webkit-full-page-media, _:future, :root [data-has-multi-selection="true"] .b
183183
box-shadow: 0 0 0 1px var(--wp-admin-theme-color);
184184
}
185185

186+
// Block visibility.
187+
&.is-hidden:not(.is-selected):not(.has-child-selected)::after {
188+
bottom: 0;
189+
content: "";
190+
left: 0;
191+
pointer-events: none;
192+
position: absolute;
193+
right: 0;
194+
top: 0;
195+
background: repeating-linear-gradient(45deg, rgba($gray-300, 0.7) 0, rgba($gray-300, 0.7) 5px, transparent 5px, transparent 10px);
196+
}
197+
186198
// Clear floats.
187199
&[data-clear="true"] {
188200
float: none;

packages/block-editor/src/components/block-list/use-block-props/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
102102
defaultClassName,
103103
isSectionBlock,
104104
canMove,
105+
isHidden,
105106
} = useContext( PrivateBlockContext );
106107

107108
// translators: %s: Type of block (i.e. Text, Image etc)
@@ -127,6 +128,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
127128
] );
128129

129130
const blockEditContext = useBlockEditContext();
131+
130132
const hasBlockBindings = !! blockEditContext[ blockBindingsKey ];
131133
const bindingsStyle =
132134
hasBlockBindings && canBindBlock( name )
@@ -183,6 +185,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) {
183185
'is-editing-disabled': isEditingDisabled,
184186
'has-editable-outline': hasEditableOutline,
185187
'has-negative-margin': hasNegativeMargin,
188+
'is-hidden': isHidden,
186189
'is-content-locked-temporarily-editing-as-blocks':
187190
isTemporarilyEditingAsBlocks,
188191
},

packages/block-editor/src/components/block-settings-menu-controls/index.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
MenuGroup,
77
__experimentalStyleProvider as StyleProvider,
88
} from '@wordpress/components';
9+
import { hasBlockSupport } from '@wordpress/blocks';
910
import { useSelect } from '@wordpress/data';
1011

1112
/**
@@ -20,13 +21,20 @@ import { store as blockEditorStore } from '../../store';
2021
import BlockModeToggle from '../block-settings-menu/block-mode-toggle';
2122
import { ModifyContentLockMenuItem } from '../content-lock';
2223
import { BlockRenameControl, useBlockRename } from '../block-rename';
24+
import { BlockVisibilityMenuItem } from '../block-visibility';
2325

2426
const { Fill, Slot } = createSlotFill( 'BlockSettingsMenuControls' );
2527

2628
const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
27-
const { selectedBlocks, selectedClientIds, isContentOnly } = useSelect(
29+
const {
30+
selectedBlocks,
31+
selectedClientIds,
32+
isContentOnly,
33+
canToggleSelectedBlocksVisibility,
34+
} = useSelect(
2835
( select ) => {
2936
const {
37+
getBlocksByClientId,
3038
getBlockNamesByClientId,
3139
getSelectedBlockClientIds,
3240
getBlockEditingMode,
@@ -38,6 +46,11 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
3846
selectedClientIds: ids,
3947
isContentOnly:
4048
getBlockEditingMode( ids[ 0 ] ) === 'contentOnly',
49+
canToggleSelectedBlocksVisibility: getBlocksByClientId(
50+
ids
51+
).every( ( block ) =>
52+
hasBlockSupport( block.name, 'blockVisibility', true )
53+
),
4154
};
4255
},
4356
[ clientIds ]
@@ -49,6 +62,8 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
4962
selectedClientIds.length === 1 && canLock && ! isContentOnly;
5063
const showRenameButton =
5164
selectedClientIds.length === 1 && canRename && ! isContentOnly;
65+
const showVisibilityButton =
66+
canToggleSelectedBlocksVisibility && ! isContentOnly;
5267

5368
// Check if current selection of blocks is Groupable or Ungroupable
5469
// and pass this props down to ConvertToGroupButton.
@@ -93,6 +108,11 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
93108
clientId={ selectedClientIds[ 0 ] }
94109
/>
95110
) }
111+
{ showVisibilityButton && (
112+
<BlockVisibilityMenuItem
113+
clientIds={ selectedClientIds }
114+
/>
115+
) }
96116
{ fills }
97117
{ selectedClientIds.length === 1 && (
98118
<ModifyContentLockMenuItem

packages/block-editor/src/components/block-toolbar/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import BlockControls from '../block-controls';
2828
import __unstableBlockToolbarLastItem from './block-toolbar-last-item';
2929
import BlockSettingsMenu from '../block-settings-menu';
3030
import { BlockLockToolbar } from '../block-lock';
31+
import { BlockVisibilityToolbar } from '../block-visibility';
3132
import { BlockGroupToolbar } from '../convert-to-group-buttons';
3233
import BlockEditVisuallyButton from '../block-edit-visually-button';
3334
import { useShowHoveredOrFocusedGestures } from './utils';
@@ -73,6 +74,7 @@ export function PrivateBlockToolbar( {
7374
showSlots,
7475
showGroupButtons,
7576
showLockButtons,
77+
showBlockVisibilityButton,
7678
showSwitchSectionStyleButton,
7779
hasFixedToolbar,
7880
isNavigationMode,
@@ -153,6 +155,7 @@ export function PrivateBlockToolbar( {
153155
showSlots: ! _isZoomOut,
154156
showGroupButtons: ! _isZoomOut,
155157
showLockButtons: ! _isZoomOut,
158+
showBlockVisibilityButton: ! _isZoomOut,
156159
showSwitchSectionStyleButton:
157160
_isZoomOut ||
158161
( isNavigationModeEnabled &&
@@ -221,6 +224,12 @@ export function PrivateBlockToolbar( {
221224
>
222225
<ToolbarGroup className="block-editor-block-toolbar__block-controls">
223226
<BlockSwitcher clientIds={ blockClientIds } />
227+
{ ! isMultiToolbar &&
228+
showBlockVisibilityButton && (
229+
<BlockVisibilityToolbar
230+
clientId={ blockClientId }
231+
/>
232+
) }
224233
{ ! isMultiToolbar &&
225234
isDefaultEditingMode &&
226235
showLockButtons && (
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { default as BlockVisibilityMenuItem } from './menu-item';
2+
export { default as BlockVisibilityToolbar } from './toolbar';
3+
export { default as useBlockVisibility } from './use-block-visibility';

0 commit comments

Comments
 (0)