PluginProbe
Gutenberg / 24.1.0
Gutenberg v24.1.0
24.1.0 24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 All 404 releases
← All changes | lib/block-supports/position.php +148 -48 23.4.0 → 24.1.0 View file →
@@ -25,25 +25,111 @@
25 25 }
26 26 }
27 27
28 28 /**
29 + * Returns the CSS rules for a position style configuration.
30 + *
31 + * @param string $selector CSS selector to scope the rules to.
32 + * @param mixed $position Position style configuration.
33 + * @param array $allowed_position_types Position types the theme supports.
34 + * @return array CSS rules, or an empty array when the configuration is not allowed.
35 + */
36 +function gutenberg_get_position_support_styles( $selector, $position, $allowed_position_types ) {
37 + $styles = array();
38 +
39 + if ( ! is_array( $position ) ) {
40 + return $styles;
41 + }
42 +
43 + $position_type = $position['type'] ?? '';
44 +
45 + if ( ! in_array( $position_type, $allowed_position_types, true ) ) {
46 + return $styles;
47 + }
48 +
49 + $sides = array( 'top', 'right', 'bottom', 'left' );
50 +
51 + foreach ( $sides as $side ) {
52 + $side_value = $position[ $side ] ?? null;
53 + if ( null !== $side_value ) {
54 + /*
55 + * For fixed or sticky top positions,
56 + * ensure the value includes an offset for the logged in admin bar.
57 + */
58 + if ( 'top' === $side ) {
59 + // Ensure 0 values can be used in `calc()` calculations.
60 + if ( '0' === $side_value || 0 === $side_value ) {
61 + $side_value = '0px';
62 + }
63 +
64 + // Ensure current side value also factors in the height of the logged in admin bar.
65 + $side_value = "calc($side_value + var(--wp-admin--admin-bar--position-offset, 0px))";
66 + }
67 +
68 + $styles[] =
69 + array(
70 + 'selector' => $selector,
71 + 'declarations' => array(
72 + $side => $side_value,
73 + ),
74 + );
75 + }
76 + }
77 +
78 + $styles[] =
79 + array(
80 + 'selector' => $selector,
81 + 'declarations' => array(
82 + 'position' => $position_type,
83 + 'z-index' => '10', // TODO: Replace hard-coded z-index value with a z-index preset approach in theme.json.
84 + ),
85 + );
86 +
87 + return $styles;
88 +}
89 +
90 +/**
29 91 * Renders position styles to the block wrapper.
30 92 *
31 - * @param string $block_content Rendered block content.
32 - * @param array $block Block object.
33 - * @return string Filtered block content.
93 + * @since 6.2.0
94 + * @since 7.2.0 Added support for viewport states.
95 + *
96 + * @param string $block_content Rendered block content.
97 + * @param array $block Block object.
98 + * @return string Filtered block content.
34 99 */
35 100 function gutenberg_render_position_support( $block_content, $block ) {
36 101 $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
37 102 $has_position_support = block_has_support( $block_type, array( 'position' ), false );
38 103
39 - if (
40 - ! $has_position_support ||
41 - empty( $block['attrs']['style']['position'] )
42 - ) {
104 + $style_attribute = $block['attrs']['style'] ?? null;
105 +
106 + if ( ! $has_position_support || ! is_array( $style_attribute ) ) {
43 107 return $block_content;
44 108 }
45 109
110 + /*
111 + * Position styles can exist in either the default state or a viewport state.
112 + */
113 + $has_position_style = ! empty( $style_attribute['position'] );
114 + if ( ! $has_position_style ) {
115 + foreach ( $style_attribute as $key => $style ) {
116 + if (
117 + is_string( $key ) &&
118 + str_starts_with( $key, '@' ) &&
119 + is_array( $style ) &&
120 + ! empty( $style['position'] )
121 + ) {
122 + $has_position_style = true;
123 + break;
124 + }
125 + }
126 + }
127 +
128 + if ( ! $has_position_style ) {
129 + return $block_content;
130 + }
131 +
46 132 $global_settings = gutenberg_get_global_settings();
47 133 $theme_has_sticky_support = $global_settings['position']['sticky'] ?? false;
48 134 $theme_has_fixed_support = $global_settings['position']['fixed'] ?? false;
49 135
@@ -55,60 +141,73 @@
55 141 if ( true === $theme_has_fixed_support ) {
56 142 $allowed_position_types[] = 'fixed';
57 143 }
58 144
59 - $style_attribute = $block['attrs']['style'] ?? null;
145 + $viewport_settings = $global_settings['viewport'] ?? null;
146 + $responsive_media_queries = WP_Theme_JSON_Gutenberg::get_viewport_media_queries( $viewport_settings );
147 +
60 148 $class_name = wp_unique_id( 'wp-container-' );
61 149 $selector = ".$class_name";
62 150 $position_styles = array();
63 - $position_type = $style_attribute['position']['type'] ?? '';
64 151 $wrapper_classes = array();
152 + $base_position = $style_attribute['position'] ?? null;
65 153
66 - if (
67 - in_array( $position_type, $allowed_position_types, true )
68 - ) {
69 - $wrapper_classes[] = $class_name;
70 - $wrapper_classes[] = 'is-position-' . $position_type;
71 - $sides = array( 'top', 'right', 'bottom', 'left' );
154 + // Default viewport (base) position styles.
155 + $base_styles = gutenberg_get_position_support_styles(
156 + $selector,
157 + $base_position,
158 + $allowed_position_types
159 + );
72 160
73 - foreach ( $sides as $side ) {
74 - $side_value = $style_attribute['position'][ $side ] ?? null;
75 - if ( null !== $side_value ) {
76 - /*
77 - * For fixed or sticky top positions,
78 - * ensure the value includes an offset for the logged in admin bar.
79 - */
80 - if (
81 - 'top' === $side &&
82 - ( 'fixed' === $position_type || 'sticky' === $position_type )
83 - ) {
84 - // Ensure 0 values can be used in `calc()` calculations.
85 - if ( '0' === $side_value || 0 === $side_value ) {
86 - $side_value = '0px';
87 - }
161 + if ( ! empty( $base_styles ) ) {
162 + $position_styles = $base_styles;
163 + $wrapper_classes[] = 'is-position-' . $base_position['type'];
164 + }
88 165
89 - // Ensure current side value also factors in the height of the logged in admin bar.
90 - $side_value = "calc($side_value + var(--wp-admin--admin-bar--position-offset, 0px))";
91 - }
166 + /*
167 + * Responsive viewport state styles. A viewport state inherits any values
168 + * it does not set from the default state, so a state that only overrides
169 + * e.g. the `top` offset keeps the base position type.
170 + */
171 + foreach ( $responsive_media_queries as $breakpoint => $media_query ) {
172 + $viewport_position_style = $style_attribute[ $breakpoint ]['position'] ?? null;
92 173
93 - $position_styles[] =
94 - array(
95 - 'selector' => $selector,
96 - 'declarations' => array(
97 - $side => $side_value,
98 - ),
99 - );
100 - }
174 + if ( empty( $viewport_position_style ) || ! is_array( $viewport_position_style ) ) {
175 + continue;
101 176 }
102 177
103 - $position_styles[] =
104 - array(
105 - 'selector' => $selector,
106 - 'declarations' => array(
107 - 'position' => $position_type,
108 - 'z-index' => '10', // TODO: Replace hard-coded z-index value with a z-index preset approach in theme.json.
178 + $viewport_position = is_array( $base_position )
179 + ? array_replace( $base_position, $viewport_position_style )
180 + : $viewport_position_style;
181 +
182 + $viewport_styles = gutenberg_get_position_support_styles(
183 + $selector,
184 + $viewport_position,
185 + $allowed_position_types
186 + );
187 +
188 + if ( ! empty( $viewport_styles ) ) {
189 + $wrapper_classes[] = 'is-position-' . $viewport_position['type'];
190 + } elseif ( ! empty( $base_styles ) ) {
191 + /*
192 + * The viewport state can explicitly clear the position type inherited from the
193 + * default state.
194 + */
195 + $viewport_styles = array(
196 + array(
197 + 'selector' => $selector,
198 + 'declarations' => array( 'position' => 'static' ),
109 199 ),
110 200 );
201 + } else {
202 + continue;
203 + }
204 +
205 + foreach ( $viewport_styles as $index => $rule ) {
206 + $viewport_styles[ $index ]['rules_group'] = $media_query;
207 + }
208 +
209 + $position_styles = array_merge( $position_styles, $viewport_styles );
111 210 }
112 211
113 212 if ( ! empty( $position_styles ) ) {
114 213 /*
@@ -124,9 +223,10 @@
124 223
125 224 // Inject class name to block container markup.
126 225 $content = new WP_HTML_Tag_Processor( $block_content );
127 226 $content->next_tag();
128 - foreach ( $wrapper_classes as $class ) {
227 + $content->add_class( $class_name );
228 + foreach ( array_unique( $wrapper_classes ) as $class ) {
129 229 $content->add_class( $class );
130 230 }
131 231 return (string) $content;
132 232 }