6
6
* @since n.e.x.t
7
7
*/
8
8
9
- /**
10
- * Gets the smaller image size if the layout width is bigger.
11
- *
12
- * It will return the smaller image size and return "px" if the layout width
13
- * is something else, e.g. min(640px, 90vw) or 90vw.
14
- *
15
- * @since 1.1.0
16
- *
17
- * @param string $layout_width The layout width.
18
- * @param int $image_width The image width.
19
- * @return string The proper width after some calculations.
20
- */
21
- function auto_sizes_get_width ( string $ layout_width , int $ image_width ): string {
22
- if ( str_ends_with ( $ layout_width , 'px ' ) ) {
23
- return $ image_width > (int ) $ layout_width ? $ layout_width : $ image_width . 'px ' ;
24
- }
25
- return $ image_width . 'px ' ;
26
- }
27
-
28
9
/**
29
10
* Primes attachment into the cache with a single database query.
30
11
*
@@ -84,6 +65,7 @@ function auto_sizes_filter_image_tag( $content, array $parsed_block, WP_Block $b
84
65
if ( ! is_string ( $ content ) ) {
85
66
return '' ;
86
67
}
68
+
87
69
$ processor = new WP_HTML_Tag_Processor ( $ content );
88
70
$ has_image = $ processor ->next_tag ( array ( 'tag_name ' => 'IMG ' ) );
89
71
@@ -99,11 +81,24 @@ function auto_sizes_filter_image_tag( $content, array $parsed_block, WP_Block $b
99
81
* @param string $size The image size data.
100
82
*/
101
83
$ filter = static function ( $ sizes , $ size ) use ( $ block ) {
102
- $ id = $ block ->attributes ['id ' ] ?? 0 ;
103
- $ alignment = $ block ->attributes ['align ' ] ?? '' ;
104
- $ width = $ block ->attributes ['width ' ] ?? '' ;
105
84
106
- return auto_sizes_calculate_better_sizes ( (int ) $ id , (string ) $ size , (string ) $ alignment , (string ) $ width );
85
+ $ id = isset ( $ block ->attributes ['id ' ] ) ? (int ) $ block ->attributes ['id ' ] : 0 ;
86
+ $ alignment = $ block ->attributes ['align ' ] ?? '' ;
87
+ $ width = isset ( $ block ->attributes ['width ' ] ) ? (int ) $ block ->attributes ['width ' ] : 0 ;
88
+ $ max_alignment = $ block ->context ['max_alignment ' ] ?? '' ;
89
+
90
+ /*
91
+ * Update width for cover block.
92
+ * See https://github.com/WordPress/gutenberg/blob/938720602082dc50a1746bd2e33faa3d3a6096d4/packages/block-library/src/cover/style.scss#L82-L87.
93
+ */
94
+ if ( 'core/cover ' === $ block ->name && in_array ( $ alignment , array ( 'left ' , 'right ' ), true ) ) {
95
+ $ size = array ( 420 , 420 );
96
+ }
97
+
98
+ $ better_sizes = auto_sizes_calculate_better_sizes ( $ id , $ size , $ alignment , $ width , $ max_alignment );
99
+
100
+ // If better sizes can't be calculated, use the default sizes.
101
+ return false !== $ better_sizes ? $ better_sizes : $ sizes ;
107
102
};
108
103
109
104
// Hook this filter early, before default filters are run.
@@ -135,50 +130,175 @@ function auto_sizes_filter_image_tag( $content, array $parsed_block, WP_Block $b
135
130
/**
136
131
* Modifies the sizes attribute of an image based on layout context.
137
132
*
138
- * @param int $id The image id.
139
- * @param string $size The image size data.
140
- * @param string $align The image alignment.
141
- * @param string $resize_width Resize image width.
142
- * @return string The sizes attribute value.
133
+ * @since n.e.x.t
134
+ *
135
+ * @param int $id The image attachment post ID.
136
+ * @param string|array{int, int} $size Image size name or array of width and height.
137
+ * @param string $align The image alignment.
138
+ * @param int $resize_width Resize image width.
139
+ * @param string $max_alignment The maximum usable layout alignment.
140
+ * @return string|false An improved sizes attribute or false if a better size cannot be calculated.
143
141
*/
144
- function auto_sizes_calculate_better_sizes ( int $ id , string $ size , string $ align , string $ resize_width ): string {
145
- $ sizes = '' ;
146
- $ image = wp_get_attachment_image_src ( $ id , $ size );
142
+ function auto_sizes_calculate_better_sizes ( int $ id , $ size , string $ align , int $ resize_width , string $ max_alignment ) {
143
+ // Without an image ID or a resize width, we cannot calculate a better size.
144
+ if ( 0 === $ id && 0 === $ resize_width ) {
145
+ return false ;
146
+ }
147
147
148
- if ( false === $ image ) {
149
- return $ sizes ;
148
+ $ image_data = wp_get_attachment_image_src ( $ id , $ size );
149
+
150
+ $ image_width = false !== $ image_data ? $ image_data [1 ] : 0 ;
151
+
152
+ // If we don't have an image width or a resize width, we cannot calculate a better size.
153
+ if ( 0 === $ image_width && 0 === $ resize_width ) {
154
+ return false ;
150
155
}
151
156
152
- // Retrieve width from the image tag itself.
153
- $ image_width = '' !== $ resize_width ? (int ) $ resize_width : $ image [1 ];
157
+ /*
158
+ * If we don't have an image width, use the resize width.
159
+ * If we have both an image width and a resize width, use the smaller of the two.
160
+ */
161
+ if ( 0 === $ image_width ) {
162
+ $ image_width = $ resize_width ;
163
+ } elseif ( 0 !== $ resize_width ) {
164
+ $ image_width = min ( $ image_width , $ resize_width );
165
+ }
166
+
167
+ // Normalize default alignment values.
168
+ $ align = '' !== $ align ? $ align : 'default ' ;
169
+
170
+ /*
171
+ * Map alignment values to a weighting value so they can be compared.
172
+ * Note that 'left' and 'right' alignments are only constrained by max alignment.
173
+ */
174
+ $ constraints = array (
175
+ 'full ' => 0 ,
176
+ 'wide ' => 1 ,
177
+ 'left ' => 2 ,
178
+ 'right ' => 2 ,
179
+ 'default ' => 3 ,
180
+ 'center ' => 3 ,
181
+ );
154
182
155
- $ layout = wp_get_global_settings ( array ( ' layout ' ) ) ;
183
+ $ alignment = $ constraints [ $ align ] > $ constraints [ $ max_alignment ] ? $ align : $ max_alignment ;
156
184
157
185
// Handle different alignment use cases.
158
- switch ( $ align ) {
186
+ switch ( $ alignment ) {
159
187
case 'full ' :
160
- $ sizes = ' 100vw ' ;
188
+ $ layout_width = auto_sizes_get_layout_width ( ' full ' ) ;
161
189
break ;
162
190
163
191
case 'wide ' :
164
- if ( array_key_exists ( 'wideSize ' , $ layout ) ) {
165
- $ sizes = sprintf ( '(max-width: %1$s) 100vw, %1$s ' , $ layout ['wideSize ' ] );
166
- }
192
+ $ layout_width = auto_sizes_get_layout_width ( 'wide ' );
167
193
break ;
168
194
169
195
case 'left ' :
170
196
case 'right ' :
171
- case 'center ' :
172
- $ sizes = sprintf ( '(max-width: %1$dpx) 100vw, %1$dpx ' , $ image_width );
197
+ $ layout_width = sprintf ( '%1$spx ' , $ image_width );
173
198
break ;
174
199
200
+ case 'center ' :
175
201
default :
176
- if ( array_key_exists ( 'contentSize ' , $ layout ) ) {
177
- $ width = auto_sizes_get_width ( $ layout ['contentSize ' ], $ image_width );
178
- $ sizes = sprintf ( '(max-width: %1$s) 100vw, %1$s ' , $ width );
179
- }
202
+ $ alignment = auto_sizes_get_layout_width ( 'default ' );
203
+ $ layout_width = sprintf ( '%1$spx ' , min ( (int ) $ alignment , $ image_width ) );
180
204
break ;
181
205
}
182
206
183
- return $ sizes ;
207
+ // Format layout width when not 'full'.
208
+ if ( 'full ' !== $ alignment ) {
209
+ $ layout_width = sprintf ( '(max-width: %1$s) 100vw, %1$s ' , $ layout_width );
210
+ }
211
+
212
+ return $ layout_width ;
213
+ }
214
+
215
+ /**
216
+ * Retrieves the layout width for an alignment defined in theme.json.
217
+ *
218
+ * @since n.e.x.t
219
+ *
220
+ * @param string $alignment The alignment value.
221
+ * @return string The alignment width based.
222
+ */
223
+ function auto_sizes_get_layout_width ( string $ alignment ): string {
224
+ $ layout = auto_sizes_get_layout_settings ();
225
+
226
+ $ layout_widths = array (
227
+ 'full ' => '100vw ' , // Todo: incorporate useRootPaddingAwareAlignments.
228
+ 'wide ' => array_key_exists ( 'wideSize ' , $ layout ) ? $ layout ['wideSize ' ] : '' ,
229
+ 'default ' => array_key_exists ( 'contentSize ' , $ layout ) ? $ layout ['contentSize ' ] : '' ,
230
+ );
231
+
232
+ return $ layout_widths [ $ alignment ] ?? '' ;
233
+ }
234
+
235
+ /**
236
+ * Filters the context keys that a block type uses.
237
+ *
238
+ * @since n.e.x.t
239
+ *
240
+ * @param string[] $uses_context Array of registered uses context for a block type.
241
+ * @param WP_Block_Type $block_type The full block type object.
242
+ * @return string[] The filtered context keys used by the block type.
243
+ */
244
+ function auto_sizes_filter_uses_context ( array $ uses_context , WP_Block_Type $ block_type ): array {
245
+ // The list of blocks that can consume outer layout context.
246
+ $ consumer_blocks = array (
247
+ 'core/cover ' ,
248
+ 'core/image ' ,
249
+ );
250
+
251
+ if ( in_array ( $ block_type ->name , $ consumer_blocks , true ) ) {
252
+ // Use array_values to reset the array keys after merging.
253
+ return array_values ( array_unique ( array_merge ( $ uses_context , array ( 'max_alignment ' ) ) ) );
254
+ }
255
+ return $ uses_context ;
256
+ }
257
+
258
+ /**
259
+ * Modifies the block context during rendering to blocks.
260
+ *
261
+ * @since n.e.x.t
262
+ *
263
+ * @param array<string, mixed> $context Current block context.
264
+ * @param array<string, mixed> $block The block being rendered.
265
+ * @return array<string, mixed> Modified block context.
266
+ */
267
+ function auto_sizes_filter_render_block_context ( array $ context , array $ block ): array {
268
+ // When no max alignment is set, the maximum is assumed to be 'full'.
269
+ $ context ['max_alignment ' ] = $ context ['max_alignment ' ] ?? 'full ' ;
270
+
271
+ // The list of blocks that can modify outer layout context.
272
+ $ provider_blocks = array (
273
+ 'core/columns ' ,
274
+ 'core/group ' ,
275
+ );
276
+
277
+ if ( in_array ( $ block ['blockName ' ], $ provider_blocks , true ) ) {
278
+ $ alignment = $ block ['attrs ' ]['align ' ] ?? '' ;
279
+
280
+ // If the container block doesn't have alignment, it's assumed to be 'default'.
281
+ if ( '' === $ alignment ) {
282
+ $ context ['max_alignment ' ] = 'default ' ;
283
+ } elseif ( 'wide ' === $ alignment ) {
284
+ $ context ['max_alignment ' ] = 'wide ' ;
285
+ }
286
+ }
287
+
288
+ return $ context ;
289
+ }
290
+
291
+ /**
292
+ * Retrieves the layout settings defined in theme.json.
293
+ *
294
+ * @since n.e.x.t
295
+ *
296
+ * @return array<string, mixed> Associative array of layout settings.
297
+ */
298
+ function auto_sizes_get_layout_settings (): array {
299
+ static $ layout = array ();
300
+ if ( count ( $ layout ) === 0 ) {
301
+ $ layout = wp_get_global_settings ( array ( 'layout ' ) );
302
+ }
303
+ return $ layout ;
184
304
}
0 commit comments