Commit eeb58253b4 for wordpress.org
commit eeb58253b420cc050d4a5ca84903deb81e766dac
Author: isabel_brison <isabel_brison@git.wordpress.org>
Date: Fri Sep 25 10:24:49 2026 +0000
Editor: enable setting position within viewport states.
Adds per-viewport output to the position block support.
Props isabel_brison, ramonopoly.
Fixes #66166.
Built from https://develop.svn.wordpress.org/trunk@63929
git-svn-id: http://core.svn.wordpress.org/trunk@63095 1a063a9b-81f0-0310-95a4-ce76da25c4cd
diff --git a/wp-includes/block-supports/position.php b/wp-includes/block-supports/position.php
index f8bc49c383..18968bb8be 100644
--- a/wp-includes/block-supports/position.php
+++ b/wp-includes/block-supports/position.php
@@ -29,10 +29,73 @@ function wp_register_position_support( $block_type ) {
}
}
+/**
+ * Returns the CSS rules for a position style configuration.
+ *
+ * @since 7.2.0
+ *
+ * @param string $selector CSS selector to scope the rules to.
+ * @param mixed $position Position style configuration.
+ * @param array $allowed_position_types Position types the theme supports.
+ * @return array CSS rules, or an empty array when the configuration is not allowed.
+ */
+function wp_get_position_support_styles( $selector, $position, $allowed_position_types ) {
+ $styles = array();
+
+ if ( ! is_array( $position ) || ! is_string( $position['type'] ?? null ) ) {
+ return $styles;
+ }
+
+ $position_type = $position['type'];
+
+ if ( ! in_array( $position_type, $allowed_position_types, true ) ) {
+ return $styles;
+ }
+
+ $sides = array( 'top', 'right', 'bottom', 'left' );
+
+ foreach ( $sides as $side ) {
+ $side_value = $position[ $side ] ?? null;
+ if ( null !== $side_value ) {
+ /*
+ * For fixed or sticky top positions,
+ * ensure the value includes an offset for the logged in admin bar.
+ */
+ if ( 'top' === $side ) {
+ // Ensure 0 values can be used in `calc()` calculations.
+ if ( '0' === $side_value || 0 === $side_value ) {
+ $side_value = '0px';
+ }
+
+ // Ensure current side value also factors in the height of the logged in admin bar.
+ $side_value = "calc($side_value + var(--wp-admin--admin-bar--position-offset, 0px))";
+ }
+
+ $styles[] = array(
+ 'selector' => $selector,
+ 'declarations' => array(
+ $side => $side_value,
+ ),
+ );
+ }
+ }
+
+ $styles[] = array(
+ 'selector' => $selector,
+ 'declarations' => array(
+ 'position' => $position_type,
+ 'z-index' => '10',
+ ),
+ );
+
+ return $styles;
+}
+
/**
* Renders position styles to the block wrapper.
*
* @since 6.2.0
+ * @since 7.2.0 Added support for viewport states.
* @access private
*
* @param string $block_content Rendered block content.
@@ -42,11 +105,31 @@ function wp_register_position_support( $block_type ) {
function wp_render_position_support( $block_content, $block ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$has_position_support = block_has_support( $block_type, 'position', false );
+ $style_attribute = $block['attrs']['style'] ?? null;
- if (
- ! $has_position_support ||
- empty( $block['attrs']['style']['position'] )
- ) {
+ if ( ! $has_position_support || ! is_array( $style_attribute ) ) {
+ return $block_content;
+ }
+
+ /*
+ * Position styles can exist in either the default state or a viewport state.
+ */
+ $has_position_style = ! empty( $style_attribute['position'] );
+ if ( ! $has_position_style ) {
+ foreach ( $style_attribute as $key => $style ) {
+ if (
+ is_string( $key ) &&
+ str_starts_with( $key, '@' ) &&
+ is_array( $style ) &&
+ ! empty( $style['position'] )
+ ) {
+ $has_position_style = true;
+ break;
+ }
+ }
+ }
+
+ if ( ! $has_position_style ) {
return $block_content;
}
@@ -63,58 +146,70 @@ function wp_render_position_support( $block_content, $block ) {
$allowed_position_types[] = 'fixed';
}
- $style_attribute = $block['attrs']['style'] ?? null;
- $class_name = wp_unique_id( 'wp-container-' );
- $selector = ".$class_name";
- $position_styles = array();
- $position_type = $style_attribute['position']['type'] ?? '';
- $wrapper_classes = array();
-
- if (
- in_array( $position_type, $allowed_position_types, true )
- ) {
- $wrapper_classes[] = $class_name;
- $wrapper_classes[] = 'is-position-' . $position_type;
- $sides = array( 'top', 'right', 'bottom', 'left' );
-
- foreach ( $sides as $side ) {
- $side_value = $style_attribute['position'][ $side ] ?? null;
- if ( null !== $side_value ) {
- /*
- * For fixed or sticky top positions,
- * ensure the value includes an offset for the logged in admin bar.
- */
- if (
- 'top' === $side &&
- ( 'fixed' === $position_type || 'sticky' === $position_type )
- ) {
- // Ensure 0 values can be used in `calc()` calculations.
- if ( '0' === $side_value || 0 === $side_value ) {
- $side_value = '0px';
- }
-
- // Ensure current side value also factors in the height of the logged in admin bar.
- $side_value = "calc($side_value + var(--wp-admin--admin-bar--position-offset, 0px))";
- }
+ $viewport_settings = $global_settings['viewport'] ?? null;
+ $responsive_media_queries = WP_Theme_JSON::get_viewport_media_queries( $viewport_settings );
+ $class_name = wp_unique_id( 'wp-container-' );
+ $selector = ".$class_name";
+ $position_styles = array();
+ $wrapper_classes = array();
+ $base_position = $style_attribute['position'] ?? null;
+
+ // Default viewport (base) position styles.
+ $base_styles = wp_get_position_support_styles(
+ $selector,
+ $base_position,
+ $allowed_position_types
+ );
+
+ if ( ! empty( $base_styles ) ) {
+ $position_styles = $base_styles;
+ $wrapper_classes[] = 'is-position-' . $base_position['type'];
+ }
- $position_styles[] =
- array(
- 'selector' => $selector,
- 'declarations' => array(
- $side => $side_value,
- ),
- );
- }
+ /*
+ * Responsive viewport state styles. A viewport state inherits any values
+ * it does not set from the default state, so a state that only overrides
+ * e.g. the `top` offset keeps the base position type.
+ */
+ foreach ( $responsive_media_queries as $breakpoint => $media_query ) {
+ $viewport_position_style = $style_attribute[ $breakpoint ]['position'] ?? null;
+
+ if ( empty( $viewport_position_style ) || ! is_array( $viewport_position_style ) ) {
+ continue;
}
- $position_styles[] =
- array(
- 'selector' => $selector,
- 'declarations' => array(
- 'position' => $position_type,
- 'z-index' => '10',
+ $viewport_position = is_array( $base_position )
+ ? array_replace( $base_position, $viewport_position_style )
+ : $viewport_position_style;
+
+ $viewport_styles = wp_get_position_support_styles(
+ $selector,
+ $viewport_position,
+ $allowed_position_types
+ );
+
+ if ( ! empty( $viewport_styles ) ) {
+ $wrapper_classes[] = 'is-position-' . $viewport_position['type'];
+ } elseif ( ! empty( $base_styles ) ) {
+ /*
+ * The viewport state can explicitly clear the position type inherited from the
+ * default state.
+ */
+ $viewport_styles = array(
+ array(
+ 'selector' => $selector,
+ 'declarations' => array( 'position' => 'static' ),
),
);
+ } else {
+ continue;
+ }
+
+ foreach ( $viewport_styles as $index => $rule ) {
+ $viewport_styles[ $index ]['rules_group'] = $media_query;
+ }
+
+ $position_styles = array_merge( $position_styles, $viewport_styles );
}
if ( ! empty( $position_styles ) ) {
@@ -132,7 +227,8 @@ function wp_render_position_support( $block_content, $block ) {
// Inject class name to block container markup.
$content = new WP_HTML_Tag_Processor( $block_content );
$content->next_tag();
- foreach ( $wrapper_classes as $class ) {
+ $content->add_class( $class_name );
+ foreach ( array_unique( $wrapper_classes ) as $class ) {
$content->add_class( $class );
}
return (string) $content;
diff --git a/wp-includes/version.php b/wp-includes/version.php
index b296dc4789..5b6518dad0 100644
--- a/wp-includes/version.php
+++ b/wp-includes/version.php
@@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
-$wp_version = '7.2-alpha-63928';
+$wp_version = '7.2-alpha-63929';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.