Skip to content
Open
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
121 changes: 119 additions & 2 deletions src/wp-includes/block-supports/block-visibility.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
*/

/**
* Render nothing if the block is hidden.
* Render nothing if the block is hidden, or add viewport visibility styles.
*
* @since 6.9.0
* @since 7.0.0 Added support for viewport visibility.
* @access private
*
* @param string $block_content Rendered block content.
Expand All @@ -23,10 +24,126 @@ function wp_render_block_visibility_support( $block_content, $block ) {
return $block_content;
}

if ( isset( $block['attrs']['metadata']['blockVisibility'] ) && false === $block['attrs']['metadata']['blockVisibility'] ) {
$block_visibility = $block['attrs']['metadata']['blockVisibility'] ?? null;

if ( false === $block_visibility ) {
return '';
}

if ( is_array( $block_visibility ) && ! empty( $block_visibility ) ) {
$viewport_config = $block_visibility['viewport'] ?? null;

if ( ! is_array( $viewport_config ) || empty( $viewport_config ) ) {
return $block_content;
}
/*
* Viewport size 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
* The array is in a future, potential JSON format, and will be centralized
* as the feature is developed.
*
* Viewport sizes as array items are defined sequentially. The first item's size is the max value.
* Each subsequent item starts after the previous size (using > operator), and its size is the max.
* The last item starts after the previous size (using > operator), and it has no max.
*/
$viewport_sizes = array(
array(
'name' => 'Mobile',
'slug' => 'mobile',
'size' => '480px',
),
array(
'name' => 'Tablet',
'slug' => 'tablet',
'size' => '782px',
),
array(
'name' => 'Desktop',
'slug' => 'desktop',
/*
* Note: the last item in the $viewport_sizes array does not technically require a 'size' key,
* as the last item's media query is calculated using `width > previous size`.
* The last item is present for validating the attribute values, and in order to indicate
* that this is the final viewport size, and to calculate the previous media query accordingly.
*/
),
);

/*
* Build media queries from viewport size definitions using the CSS range syntax.
* Could be absorbed into the style engine,
* as well as classname building, and declaration of the display property, if required.
*/
$viewport_media_queries = array();
$previous_size = null;
foreach ( $viewport_sizes as $index => $viewport_size ) {
// First item: width <= size.
if ( 0 === $index ) {
$viewport_media_queries[ $viewport_size['slug'] ] = "@media (width <= {$viewport_size['size']})";
} elseif ( count( $viewport_sizes ) - 1 === $index && $previous_size ) {
// Last item: width > previous size.
$viewport_media_queries[ $viewport_size['slug'] ] = "@media (width > $previous_size)";
} else {
// Middle items: previous size < width <= size.
$viewport_media_queries[ $viewport_size['slug'] ] = "@media ({$previous_size} < width <= {$viewport_size['size']})";
}

$previous_size = $viewport_size['size'] ?? null;
}

$hidden_on = array();

// Collect which viewport the block is hidden on (only known viewport sizes).
foreach ( $viewport_config as $viewport_config_size => $is_visible ) {
if ( false === $is_visible && isset( $viewport_media_queries[ $viewport_config_size ] ) ) {
$hidden_on[] = $viewport_config_size;
}
}

// If no viewport sizes have visibility set to false, return unchanged.
if ( empty( $hidden_on ) ) {
return $block_content;
}

// Maintain consistent order of viewport sizes for class name generation.
sort( $hidden_on );

$css_rules = array();
$class_names = array();

foreach ( $hidden_on as $hidden_viewport_size ) {
/*
* If these values ever become user-defined,
* they should be sanitized and kebab-cased.
*/
$visibility_class = 'wp-block-hidden-' . $hidden_viewport_size;
$class_names[] = $visibility_class;
$css_rules[] = array(
'selector' => '.' . $visibility_class,
'declarations' => array(
'display' => 'none !important',
),
'rules_group' => $viewport_media_queries[ $hidden_viewport_size ],
);
}

wp_style_engine_get_stylesheet_from_css_rules(
$css_rules,
array(
'context' => 'block-supports',
'prettify' => false,
)
);

if ( ! empty( $block_content ) ) {
$processor = new WP_HTML_Tag_Processor( $block_content );
if ( $processor->next_tag() ) {
$processor->add_class( implode( ' ', $class_names ) );
$block_content = $processor->get_updated_html();
}
}
}

return $block_content;
}

Expand Down
2 changes: 2 additions & 0 deletions src/wp-includes/kses.php
Original file line number Diff line number Diff line change
Expand Up @@ -2626,6 +2626,8 @@ function safecss_filter_attr( $css, $deprecated = '' ) {
'column-span',
'column-width',

'display',

'color',
'filter',
'font',
Expand Down
Loading
Loading