WordPress 7.0 is out, and block visibility in WordPress 7.0 is finally native. For years we hacked together custom CSS classes or leaned on a third-party plugin to hide a hero image on mobile or a sidebar on desktop. The new controls handle that, but there is a gotcha in how the blocks render that is worth knowing before your next deploy.
DOM removal versus CSS hiding
Since 6.9 the choice was binary. Set blockVisibility: false in the metadata and the block was gone: it never rendered into the DOM, so the browser never saw the markup at all.
The viewport rules in block visibility in WordPress 7.0 work differently. You pick mobile, tablet or desktop, and a block hidden for one of them is still rendered in the DOM. The hiding happens in CSS with display: none, through responsive utility classes WordPress injects from your selection.
So a heavy 10MB video block hidden on mobile through the viewport settings is still downloaded by the browser. It just never shows up on screen. When you need the weight gone rather than invisible, the global blockVisibility: false is still the one to reach for.
The new metadata structure
If you build custom blocks or parse block markup on the server, your logic probably broke. blockVisibility is no longer a boolean. It is a nested object now, so it can carry the new breakpoints.
{
"metadata": {
"blockVisibility": {
"viewport": {
"mobile": false,
"tablet": true,
"desktop": true
}
}
}
}
The viewport key sits one level down to leave room for later rules such as user roles or time-based visibility, both expected in WordPress 7.1. The Gutenberg issue #75707 tracks the work.
Refactoring your server-side logic
If your theme or plugin transforms block markup on the server, somewhere in there is a check for $metadata['blockVisibility'] === false. On WordPress 7.0 that comparison quietly fails, because the value can be an array. The check has to accept the old scalar and the new object.
This is the version I have been dropping into client projects:
<?php
/**
* Safely check if a block should be visible based on WP 7.0 metadata.
*
* @param array $block_attributes The block attributes array.
* @return bool
*/
function bbioon_is_block_visible_server_side( $block_attributes ) {
$metadata = $block_attributes['metadata'] ?? [];
if ( ! isset( $metadata['blockVisibility'] ) ) {
return true;
}
// Handle legacy boolean (WP 6.9 style)
if ( is_bool( $metadata['blockVisibility'] ) ) {
return $metadata['blockVisibility'];
}
// Handle WP 7.0 viewport object
if ( is_array( $metadata['blockVisibility'] ) && isset( $metadata['blockVisibility']['viewport'] ) ) {
// Note: Viewport hiding is usually handled via CSS classes.
// We only return false here if the block is hidden globally.
return true;
}
return true;
}
I went through the rest of the release in my breakdown of the WordPress 7.0 features for developers.
What is coming in WordPress 7.1
7.0 ships with fixed breakpoints. That covers 90% of use cases and is too rigid for the rest, which is where most agency work sits. The 7.1 roadmap adds theme.json integration, so you can define your own viewport labels and pixel widths. That is the control people have been asking for since the first version of the Site Editor.
If block visibility in WordPress 7.0 is eating your dev hours, I can take it off your plate. I have been wrestling with WordPress since the 4.x days and have watched these API shifts land dozens of times.
What to check before you ship
Hidden does not mean absent. In block visibility in WordPress 7.0 it usually means hidden with CSS, which matters if you are chasing Core Web Vitals: a hidden image still counts toward LCP when it is the largest element in the DOM, even though nobody on a phone ever sees it. Update your metadata parsers now, and watch 7.1 for the custom breakpoints.