From 766127022e3135c193c592bdd4b35724e99492ce Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 14 Jan 2026 16:50:06 +1100 Subject: [PATCH 1/3] Restructuring viewport configuration. Update related components to utilize a nested 'viewport' object for visibility settings, ensuring consistent behavior across the block editor. Adjust tests to reflect the new structure and maintain functionality. --- lib/block-supports/block-visibility.php | 10 +++- .../src/components/block-visibility/modal.js | 26 ++++++----- .../test/use-block-visibility.js | 46 +++++++++++-------- .../components/block-visibility/test/utils.js | 32 +++++++++---- .../block-visibility/use-block-visibility.js | 2 +- .../src/components/block-visibility/utils.js | 10 +++- .../src/store/private-selectors.js | 24 ++++++---- .../src/store/test/private-selectors.js | 23 ++++++---- 8 files changed, 115 insertions(+), 58 deletions(-) diff --git a/lib/block-supports/block-visibility.php b/lib/block-supports/block-visibility.php index 6c1466d122e2e8..89bd3f909d28d6 100644 --- a/lib/block-supports/block-visibility.php +++ b/lib/block-supports/block-visibility.php @@ -30,6 +30,14 @@ function gutenberg_render_block_visibility_support( $block_content, $block ) { } if ( is_array( $block_visibility ) && ! empty( $block_visibility ) ) { + // Get viewport configuration from nested structure. + $viewport_config = $block_visibility['viewport'] ?? null; + + // If no viewport config, return unchanged. + if ( ! is_array( $viewport_config ) || empty( $viewport_config ) ) { + return $block_content; + } + /* * Breakpoints definitions are in several places in WordPress packages. * The following are taken from: https://github.com/WordPress/gutenberg/blob/trunk/packages/base-styles/_breakpoints.scss @@ -86,7 +94,7 @@ function gutenberg_render_block_visibility_support( $block_content, $block ) { $hidden_on = array(); // Collect which breakpoints the block is hidden on (only known breakpoints). - foreach ( $block_visibility as $breakpoint => $is_visible ) { + foreach ( $viewport_config as $breakpoint => $is_visible ) { if ( false === $is_visible && isset( $breakpoint_queries[ $breakpoint ] ) ) { $hidden_on[] = $breakpoint; } diff --git a/packages/block-editor/src/components/block-visibility/modal.js b/packages/block-editor/src/components/block-visibility/modal.js index 657e2b336c5a18..a8bbd997e25193 100644 --- a/packages/block-editor/src/components/block-visibility/modal.js +++ b/packages/block-editor/src/components/block-visibility/modal.js @@ -160,18 +160,20 @@ export default function BlockVisibilityModal( { clientIds, onClose } ) { event.preventDefault(); const newVisibility = hideEverywhere ? false - : BLOCK_VISIBILITY_VIEWPORT_ENTRIES.reduce( - ( acc, [ , { key } ] ) => { - if ( viewportChecked[ key ] ) { - // Values are inverted to hide the block on the selected viewport. - // In the UI, the checkbox is checked (true) when the block is hidden on the selected viewport, - // so 'false' means hide the block on the selected viewport. - acc[ key ] = false; - } - return acc; - }, - {} - ); + : { + viewport: BLOCK_VISIBILITY_VIEWPORT_ENTRIES.reduce( + ( acc, [ , { key } ] ) => { + if ( viewportChecked[ key ] ) { + // Values are inverted to hide the block on the selected viewport. + // In the UI, the checkbox is checked (true) when the block is hidden on the selected viewport, + // so 'false' means hide the block on the selected viewport. + acc[ key ] = false; + } + return acc; + }, + {} + ), + }; const attributesByClientId = Object.fromEntries( blocks.map( ( { clientId, attributes } ) => [ clientId, diff --git a/packages/block-editor/src/components/block-visibility/test/use-block-visibility.js b/packages/block-editor/src/components/block-visibility/test/use-block-visibility.js index e878e5f2fc886a..22d2e14c42ba59 100644 --- a/packages/block-editor/src/components/block-visibility/test/use-block-visibility.js +++ b/packages/block-editor/src/components/block-visibility/test/use-block-visibility.js @@ -52,7 +52,7 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { - blockVisibility: { mobile: false }, + blockVisibility: { viewport: { mobile: false } }, deviceType: 'mobile', } ) ); @@ -66,9 +66,11 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { blockVisibility: { - mobile: true, - tablet: false, - desktop: false, + viewport: { + mobile: true, + tablet: false, + desktop: false, + }, }, deviceType: 'mobile', } ) @@ -82,7 +84,7 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { - blockVisibility: { tablet: false }, + blockVisibility: { viewport: { tablet: false } }, deviceType: 'tablet', } ) ); @@ -98,7 +100,7 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { - blockVisibility: { desktop: false }, + blockVisibility: { viewport: { desktop: false } }, deviceType: 'desktop', } ) ); @@ -116,7 +118,7 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { - blockVisibility: { mobile: false }, + blockVisibility: { viewport: { mobile: false } }, deviceType: 'desktop', } ) ); @@ -133,9 +135,11 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { blockVisibility: { - mobile: true, - tablet: false, - desktop: false, + viewport: { + mobile: true, + tablet: false, + desktop: false, + }, }, deviceType: 'desktop', } ) @@ -152,7 +156,7 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { - blockVisibility: { tablet: false }, + blockVisibility: { viewport: { tablet: false } }, deviceType: 'desktop', } ) ); @@ -169,9 +173,11 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { blockVisibility: { - mobile: false, - tablet: true, - desktop: false, + viewport: { + mobile: false, + tablet: true, + desktop: false, + }, }, deviceType: 'desktop', } ) @@ -188,7 +194,7 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { - blockVisibility: { desktop: false }, + blockVisibility: { viewport: { desktop: false } }, deviceType: 'desktop', } ) ); @@ -205,9 +211,11 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { blockVisibility: { - mobile: false, - tablet: false, - desktop: true, + viewport: { + mobile: false, + tablet: false, + desktop: true, + }, }, deviceType: 'desktop', } ) @@ -306,7 +314,7 @@ describe( 'useBlockVisibility', () => { const { result } = renderHook( () => useBlockVisibility( { - blockVisibility: { desktop: false }, + blockVisibility: { viewport: { desktop: false } }, } ) ); diff --git a/packages/block-editor/src/components/block-visibility/test/utils.js b/packages/block-editor/src/components/block-visibility/test/utils.js index f88cf60e6025d4..a5d6592d80e8e0 100644 --- a/packages/block-editor/src/components/block-visibility/test/utils.js +++ b/packages/block-editor/src/components/block-visibility/test/utils.js @@ -21,7 +21,9 @@ describe( 'block-visibility utils', () => { { attributes: { metadata: { - blockVisibility: {}, + blockVisibility: { + viewport: {}, + }, }, }, }, @@ -75,7 +77,9 @@ describe( 'block-visibility utils', () => { attributes: { metadata: { blockVisibility: { - mobile: false, + viewport: { + mobile: false, + }, }, }, }, @@ -83,7 +87,9 @@ describe( 'block-visibility utils', () => { { attributes: { metadata: { - blockVisibility: {}, + blockVisibility: { + viewport: {}, + }, }, }, }, @@ -105,7 +111,9 @@ describe( 'block-visibility utils', () => { { attributes: { metadata: { - blockVisibility: {}, + blockVisibility: { + viewport: {}, + }, }, }, }, @@ -122,7 +130,9 @@ describe( 'block-visibility utils', () => { attributes: { metadata: { blockVisibility: { - mobile: false, + viewport: { + mobile: false, + }, }, }, }, @@ -188,7 +198,9 @@ describe( 'block-visibility utils', () => { { attributes: { metadata: { - blockVisibility: {}, + blockVisibility: { + viewport: {}, + }, }, }, }, @@ -245,7 +257,9 @@ describe( 'block-visibility utils', () => { attributes: { metadata: { blockVisibility: { - mobile: false, + viewport: { + mobile: false, + }, }, }, }, @@ -254,7 +268,9 @@ describe( 'block-visibility utils', () => { attributes: { metadata: { blockVisibility: { - tablet: false, + viewport: { + tablet: false, + }, }, }, }, diff --git a/packages/block-editor/src/components/block-visibility/use-block-visibility.js b/packages/block-editor/src/components/block-visibility/use-block-visibility.js index 450c7460425164..16525d7900b7ca 100644 --- a/packages/block-editor/src/components/block-visibility/use-block-visibility.js +++ b/packages/block-editor/src/components/block-visibility/use-block-visibility.js @@ -55,7 +55,7 @@ export default function useBlockVisibility( options = {} ) { if ( window.__experimentalHideBlocksBasedOnScreenSize && - blockVisibility?.[ currentViewport ] === false + blockVisibility?.viewport?.[ currentViewport ] === false ) { return true; } diff --git a/packages/block-editor/src/components/block-visibility/utils.js b/packages/block-editor/src/components/block-visibility/utils.js index 949fc333919da0..460283ea291e0b 100644 --- a/packages/block-editor/src/components/block-visibility/utils.js +++ b/packages/block-editor/src/components/block-visibility/utils.js @@ -27,6 +27,14 @@ function isBlockHiddenForViewport( block, viewport ) { return false; } + // Get viewport configuration from nested structure. + const viewportConfig = blockVisibility.viewport; + + // If no viewport config, block is not hidden for any specific viewport. + if ( ! viewportConfig || 'object' !== typeof viewportConfig ) { + return false; + } + // Check if the viewport is valid. if ( ! BLOCK_VISIBILITY_VIEWPORT_ENTRIES.some( @@ -37,7 +45,7 @@ function isBlockHiddenForViewport( block, viewport ) { } // Check if the specific viewport is hidden. - return blockVisibility[ viewport ] === false; + return viewportConfig[ viewport ] === false; } /** diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index 0d6058bac55ce8..d9ed0b36f226ad 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -733,11 +733,15 @@ export const isBlockHidden = ( state, clientId ) => { // Check viewport-specific hiding based on current device preview // Only apply when a device is explicitly selected. if ( typeof blockVisibility === 'object' && blockVisibility !== null ) { - const settings = getSettings( state ); - const viewportType = - settings[ deviceTypeKey ] ?? BLOCK_VISIBILITY_VIEWPORTS.desktop.key; - const viewportKey = viewportType.toLowerCase(); - return blockVisibility?.[ viewportKey ] === false; + const viewportConfig = blockVisibility.viewport; + if ( viewportConfig && typeof viewportConfig === 'object' ) { + const settings = getSettings( state ); + const viewportType = + settings[ deviceTypeKey ] ?? + BLOCK_VISIBILITY_VIEWPORTS.desktop.key; + const viewportKey = viewportType.toLowerCase(); + return viewportConfig[ viewportKey ] === false; + } } return false; @@ -795,9 +799,13 @@ export const areBlocksHiddenAnywhere = ( state, clientIds ) => { } // Check viewport-specific visibility. - return BLOCK_VISIBILITY_VIEWPORT_ENTRIES.some( - ( [ , { key } ] ) => blockVisibility?.[ key ] === false - ); + const viewportConfig = blockVisibility.viewport; + if ( viewportConfig && typeof viewportConfig === 'object' ) { + return BLOCK_VISIBILITY_VIEWPORT_ENTRIES.some( + ( [ , { key } ] ) => viewportConfig[ key ] === false + ); + } + return false; } ); }; diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index 248eb54182eb5f..8ec48a1b90d2b6 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -1198,14 +1198,16 @@ describe( 'private selectors', () => { it( 'returns false when experimental flag is disabled and block has breakpoint visibility', () => { window.__experimentalHideBlocksBasedOnScreenSize = false; - const state = createState( { mobile: false, tablet: true } ); + const state = createState( { + viewport: { mobile: false, tablet: true }, + } ); const result = isBlockHidden( state, 'test-block' ); expect( result ).toBe( false ); } ); it( 'returns false when Desktop is selected and block has breakpoint visibility', () => { const state = createState( - { mobile: false, tablet: true }, + { viewport: { mobile: false, tablet: true } }, 'Desktop' ); const result = isBlockHidden( state, 'test-block' ); @@ -1213,14 +1215,17 @@ describe( 'private selectors', () => { } ); it( 'returns true when Desktop is selected and block is hidden on desktop', () => { - const state = createState( { desktop: false }, 'Desktop' ); + const state = createState( + { viewport: { desktop: false } }, + 'Desktop' + ); const result = isBlockHidden( state, 'test-block' ); expect( result ).toBe( true ); } ); it( 'returns true when Tablet is selected and block is hidden on tablet', () => { const state = createState( - { mobile: true, tablet: false }, + { viewport: { mobile: true, tablet: false } }, 'Tablet' ); const result = isBlockHidden( state, 'test-block' ); @@ -1229,7 +1234,7 @@ describe( 'private selectors', () => { it( 'returns true when Mobile is selected and block is hidden on mobile', () => { const state = createState( - { mobile: false, tablet: true }, + { viewport: { mobile: false, tablet: true } }, 'Mobile' ); const result = isBlockHidden( state, 'test-block' ); @@ -1238,7 +1243,7 @@ describe( 'private selectors', () => { it( 'returns false when Tablet is selected and block is visible on tablet', () => { const state = createState( - { mobile: false, tablet: true }, + { viewport: { mobile: false, tablet: true } }, 'Tablet' ); const result = isBlockHidden( state, 'test-block' ); @@ -1295,8 +1300,10 @@ describe( 'private selectors', () => { { metadata: { blockVisibility: { - mobile: false, - tablet: true, + viewport: { + mobile: false, + tablet: true, + }, }, }, }, From 0dd8b97cd443546e2195052e61f2cec38d346c90 Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 14 Jan 2026 16:59:00 +1100 Subject: [PATCH 2/3] backport --- backport-changelog/7.0/10629.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backport-changelog/7.0/10629.md b/backport-changelog/7.0/10629.md index cc9b838c552920..034603dc2bea4e 100644 --- a/backport-changelog/7.0/10629.md +++ b/backport-changelog/7.0/10629.md @@ -2,4 +2,5 @@ https://github.com/WordPress/wordpress-develop/pull/10629 * https://github.com/WordPress/gutenberg/pull/73994 * https://github.com/WordPress/gutenberg/pull/74379 -* https://github.com/WordPress/gutenberg/pull/74526 \ No newline at end of file +* https://github.com/WordPress/gutenberg/pull/74526 +* https://github.com/WordPress/gutenberg/pull/74602 \ No newline at end of file From c9ca2181ebe6a03be4f935cc5ef439759eb1be5f Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 14 Jan 2026 17:12:19 +1100 Subject: [PATCH 3/3] tests... unit! --- .../block-supports/block-visibility-test.php | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/phpunit/block-supports/block-visibility-test.php b/phpunit/block-supports/block-visibility-test.php index e64a2422d4e133..c9d430c0c31bb7 100644 --- a/phpunit/block-supports/block-visibility-test.php +++ b/phpunit/block-supports/block-visibility-test.php @@ -160,7 +160,9 @@ public function test_block_visibility_support_generated_css_with_mobile_breakpoi 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'mobile' => false, + 'viewport' => array( + 'mobile' => false, + ), ), ), ), @@ -193,7 +195,9 @@ public function test_block_visibility_support_generated_css_with_tablet_breakpoi 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'tablet' => false, + 'viewport' => array( + 'tablet' => false, + ), ), ), ), @@ -226,7 +230,9 @@ public function test_block_visibility_support_generated_css_with_desktop_breakpo 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'desktop' => false, + 'viewport' => array( + 'desktop' => false, + ), ), ), ), @@ -259,8 +265,10 @@ public function test_block_visibility_support_generated_css_with_multiple_breakp 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'mobile' => false, - 'desktop' => false, + 'viewport' => array( + 'mobile' => false, + 'desktop' => false, + ), ), ), ), @@ -297,9 +305,11 @@ public function test_block_visibility_support_generated_css_with_all_breakpoints 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'mobile' => true, - 'tablet' => true, - 'desktop' => true, + 'viewport' => array( + 'mobile' => true, + 'tablet' => true, + 'desktop' => true, + ), ), ), ), @@ -324,9 +334,11 @@ public function test_block_visibility_support_generated_css_with_all_breakpoints 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'mobile' => false, - 'tablet' => false, - 'desktop' => false, + 'viewport' => array( + 'mobile' => false, + 'tablet' => false, + 'desktop' => false, + ), ), ), ), @@ -374,9 +386,11 @@ public function test_block_visibility_support_generated_css_with_unknown_breakpo 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'mobile' => false, - 'unknownBreak' => false, - 'largeScreen' => false, + 'viewport' => array( + 'mobile' => false, + 'unknownBreak' => false, + 'largeScreen' => false, + ), ), ), ), @@ -405,7 +419,9 @@ public function test_block_visibility_support_generated_css_with_empty_content() 'attrs' => array( 'metadata' => array( 'blockVisibility' => array( - 'mobile' => false, + 'viewport' => array( + 'mobile' => false, + ), ), ), ),