Skip to content

Commit f84aed9

Browse files
authored
Merge branch 'WordPress:trunk' into trunk
2 parents 881e8f7 + 4816134 commit f84aed9

14 files changed

Lines changed: 518 additions & 25 deletions

src/wp-includes/abilities-api.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,13 @@
264264
* @type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments
265265
* will have no additional effect on its environment.
266266
* }
267+
* @type bool $public Optional. Whether the ability is intended to be publicly
268+
* available to clients. When true, channel-specific exposure
269+
* flags such as `$show_in_rest` default to true. An explicitly
270+
* set channel flag always takes precedence.
267271
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API.
268272
* When true, the ability can be invoked via HTTP requests.
269-
* Default false.
273+
* Default is the value of `$public` when set, false otherwise.
270274
* }
271275
* @type string $ability_class Optional. Fully-qualified custom class name to instantiate
272276
* instead of the default `WP_Ability` class. The custom class

src/wp-includes/abilities-api/class-wp-abilities-registry.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ final class WP_Abilities_Registry {
7171
* @type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments
7272
* will have no additional effect on its environment.
7373
* }
74-
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false.
74+
* @type bool $public Optional. Whether the ability is intended to be publicly
75+
* available to clients. When true, channel-specific exposure
76+
* flags such as `$show_in_rest` default to true. An explicitly
77+
* set channel flag always takes precedence.
78+
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API.
79+
* Default is the value of `$public` when set, false otherwise.
7580
* }
7681
* @type string $ability_class Optional. Custom class to instantiate instead of WP_Ability.
7782
* }
@@ -120,7 +125,11 @@ public function register( string $name, array $args ): ?WP_Ability {
120125
* Optional. Additional metadata for the ability.
121126
*
122127
* @type array<string, bool|string> $annotations Optional. Annotation metadata for the ability.
123-
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false.
128+
* @type bool $public Optional. Whether the ability is intended to be
129+
* publicly available to clients. Seeds the default for
130+
* channel-specific exposure flags like `$show_in_rest`.
131+
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API.
132+
* Default is the value of `$public` when set, false otherwise.
124133
* }
125134
* @type string $ability_class Optional. Custom class to instantiate instead of WP_Ability.
126135
* }

src/wp-includes/abilities-api/class-wp-ability.php

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,12 @@ class WP_Ability {
160160
* @type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments
161161
* will have no additional effect on its environment.
162162
* }
163-
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false.
163+
* @type bool $public Optional. Whether the ability is intended to be publicly
164+
* available to clients. When true, channel-specific exposure
165+
* flags such as `$show_in_rest` default to true. An explicitly
166+
* set channel flag always takes precedence.
167+
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API.
168+
* Default is the value of `$public` when set, false otherwise.
164169
* }
165170
* }
166171
*/
@@ -224,7 +229,12 @@ public function __construct( string $name, array $args ) {
224229
* @type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments
225230
* will have no additional effect on its environment.
226231
* }
227-
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API. Default false.
232+
* @type bool $public Optional. Whether the ability is intended to be publicly
233+
* available to clients. When true, channel-specific exposure
234+
* flags such as `$show_in_rest` default to true. An explicitly
235+
* set channel flag always takes precedence.
236+
* @type bool $show_in_rest Optional. Whether to expose this ability in the REST API.
237+
* Default is the value of `$public` when set, false otherwise.
228238
* }
229239
* }
230240
* @return array<string, mixed> {
@@ -252,7 +262,9 @@ public function __construct( string $name, array $args ) {
252262
* @type bool|null $idempotent If true, calling the ability repeatedly with the same arguments
253263
* will have no additional effect on its environment.
254264
* }
255-
* @type bool $show_in_rest Whether to expose this ability in the REST API. Default false.
265+
* @type bool $public Whether the ability is intended to be publicly available
266+
* to clients. Only present when provided during registration.
267+
* @type bool $show_in_rest Whether to expose this ability in the REST API.
256268
* }
257269
* }
258270
* @throws InvalidArgumentException if an argument is invalid.
@@ -322,14 +334,27 @@ protected function prepare_properties( array $args ): array {
322334
);
323335
}
324336

337+
if ( isset( $args['meta']['public'] ) && ! is_bool( $args['meta']['public'] ) ) {
338+
throw new InvalidArgumentException(
339+
__( 'The ability meta should provide a valid `public` boolean.' )
340+
);
341+
}
342+
325343
// Set defaults for optional meta.
326-
$args['meta'] = wp_parse_args(
344+
$args['meta'] = wp_parse_args(
327345
$args['meta'] ?? array(),
328346
array(
329-
'annotations' => static::$default_annotations,
330-
'show_in_rest' => self::DEFAULT_SHOW_IN_REST,
347+
'annotations' => static::$default_annotations,
331348
)
332349
);
350+
351+
/*
352+
* Resolve `show_in_rest` from most specific to least specific: an explicit
353+
* `show_in_rest` value wins, then the high-level `public` flag seeds the
354+
* default, then the built-in default applies.
355+
*/
356+
$args['meta']['show_in_rest'] = $args['meta']['show_in_rest'] ?? $args['meta']['public'] ?? self::DEFAULT_SHOW_IN_REST;
357+
333358
$args['meta']['annotations'] = wp_parse_args(
334359
$args['meta']['annotations'],
335360
static::$default_annotations

src/wp-includes/block-supports/dimensions.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function wp_apply_dimensions_support( $block_type, $block_attributes ) {
6464
}
6565

6666
$dimensions_block_styles = array();
67-
$supported_features = array( 'minHeight', 'height', 'width' );
67+
$supported_features = array( 'minHeight', 'minWidth', 'height', 'width' );
6868

6969
foreach ( $supported_features as $feature ) {
7070
$has_support = block_has_support( $block_type, array( 'dimensions', $feature ), false );

src/wp-includes/class-wp-theme-json.php

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class WP_Theme_JSON {
248248
* @since 6.7.0 Added `background-attachment` property.
249249
* @since 7.0.0 Added `dimensions.width` and `dimensions.height`.
250250
* Added `text-indent` property.
251-
* @since 7.1.0 Added `text-shadow` property.
251+
* @since 7.1.0 Added `min-width` and `text-shadow`.
252252
* @var array
253253
*/
254254
const PROPERTIES_METADATA = array(
@@ -295,6 +295,7 @@ class WP_Theme_JSON {
295295
'margin-bottom' => array( 'spacing', 'margin', 'bottom' ),
296296
'margin-left' => array( 'spacing', 'margin', 'left' ),
297297
'min-height' => array( 'dimensions', 'minHeight' ),
298+
'min-width' => array( 'dimensions', 'minWidth' ),
298299
'outline-color' => array( 'outline', 'color' ),
299300
'outline-offset' => array( 'outline', 'offset' ),
300301
'outline-style' => array( 'outline', 'style' ),
@@ -417,7 +418,7 @@ class WP_Theme_JSON {
417418
* Added support for `dimensions.width` and `dimensions.height`.
418419
* Added support for `typography.textIndent`.
419420
* @since 7.1.0 Added `viewport` property.
420-
* Added support for `background.gradient` and `blockVisibility.allowEditing`.
421+
* Added support for `background.gradient`, `dimensions.minWidth` and `blockVisibility.allowEditing`.
421422
* @var array
422423
*/
423424
const VALID_SETTINGS = array(
@@ -460,6 +461,7 @@ class WP_Theme_JSON {
460461
'dimensionSizes' => null,
461462
'height' => null,
462463
'minHeight' => null,
464+
'minWidth' => null,
463465
'width' => null,
464466
),
465467
'layout' => array(
@@ -563,8 +565,8 @@ class WP_Theme_JSON {
563565
* @since 6.5.0 Added support for `dimensions.aspectRatio`.
564566
* @since 6.6.0 Added `background` sub properties to top-level only.
565567
* @since 7.0.0 Added support for `dimensions.width` and `dimensions.height`.
566-
* @since 7.1.0 Added `background.gradient`.
567-
* @since 7.1.0 Added support for `typography.textShadow`.
568+
* @since 7.1.0 Added support for `background.gradient`,`dimensions.minWidth`,
569+
* and `typography.textShadow`.
568570
* @var array
569571
*/
570572
const VALID_STYLES = array(
@@ -595,6 +597,7 @@ class WP_Theme_JSON {
595597
'aspectRatio' => null,
596598
'height' => null,
597599
'minHeight' => null,
600+
'minWidth' => null,
598601
'width' => null,
599602
),
600603
'filter' => array(
@@ -1035,6 +1038,7 @@ public static function get_element_class_name( $element ) {
10351038
* @since 6.5.0 Added `background.backgroundSize` and `dimensions.aspectRatio`.
10361039
* @since 7.0.0 Added `dimensions.width` and `dimensions.height`.
10371040
* @since 7.1.0 Added `background.gradient`.
1041+
* Added `dimensions.minWidth`.
10381042
* @var array
10391043
*/
10401044
const APPEARANCE_TOOLS_OPT_INS = array(
@@ -1052,6 +1056,7 @@ public static function get_element_class_name( $element ) {
10521056
array( 'dimensions', 'aspectRatio' ),
10531057
array( 'dimensions', 'height' ),
10541058
array( 'dimensions', 'minHeight' ),
1059+
array( 'dimensions', 'minWidth' ),
10551060
array( 'dimensions', 'width' ),
10561061
array( 'position', 'sticky' ),
10571062
array( 'spacing', 'blockGap' ),
@@ -2480,21 +2485,89 @@ protected function get_css_variables( $nodes, $origins ) {
24802485
continue;
24812486
}
24822487

2483-
$selector = $metadata['selector'];
2488+
$selector = $metadata['selector'];
2489+
$feature_selectors = $metadata['selectors'] ?? array();
2490+
$node = _wp_array_get( $this->theme_json, $metadata['path'], array() );
2491+
2492+
/*
2493+
* Group preset declarations by selector. Blocks that define
2494+
* feature-level selectors need their preset CSS variables
2495+
* output under that feature selector instead of the block's
2496+
* root selector.
2497+
*/
2498+
$vars_by_selector = array();
2499+
$vars_by_selector[ $selector ] = array();
2500+
2501+
foreach ( static::PRESETS_METADATA as $preset_metadata ) {
2502+
if ( empty( $preset_metadata['css_vars'] ) ) {
2503+
continue;
2504+
}
2505+
2506+
$values_by_slug = static::get_settings_values_by_slug( $node, $preset_metadata, $origins );
2507+
if ( empty( $values_by_slug ) ) {
2508+
continue;
2509+
}
2510+
2511+
$target = static::get_feature_selector( $feature_selectors, $preset_metadata['path'][0], $selector );
2512+
2513+
if ( ! isset( $vars_by_selector[ $target ] ) ) {
2514+
$vars_by_selector[ $target ] = array();
2515+
}
2516+
2517+
foreach ( $values_by_slug as $slug => $value ) {
2518+
$vars_by_selector[ $target ][] = array(
2519+
'name' => static::replace_slug_in_string( $preset_metadata['css_vars'], $slug ),
2520+
'value' => $value,
2521+
);
2522+
}
2523+
}
24842524

2485-
$node = _wp_array_get( $this->theme_json, $metadata['path'], array() );
2486-
$declarations = static::compute_preset_vars( $node, $origins );
2487-
$theme_vars_declarations = static::compute_theme_vars( $node );
2488-
foreach ( $theme_vars_declarations as $theme_vars_declaration ) {
2489-
$declarations[] = $theme_vars_declaration;
2525+
// Theme vars always use the block's default selector.
2526+
foreach ( static::compute_theme_vars( $node ) as $theme_var ) {
2527+
$vars_by_selector[ $selector ][] = $theme_var;
24902528
}
24912529

2492-
$stylesheet .= static::to_ruleset( $selector, $declarations );
2530+
foreach ( $vars_by_selector as $rule_selector => $declarations ) {
2531+
$stylesheet .= static::to_ruleset( $rule_selector, $declarations );
2532+
}
24932533
}
24942534

24952535
return $stylesheet;
24962536
}
24972537

2538+
/**
2539+
* Returns the appropriate selector for a block support feature's
2540+
* preset CSS variables.
2541+
*
2542+
* If the block defines a feature-level selector (as a string or an
2543+
* object with a `root` key), that selector is returned. Otherwise,
2544+
* the block's default selector is used.
2545+
*
2546+
* @since 7.1.0
2547+
*
2548+
* @param array<string, string|array<string, string>> $feature_selectors The block's feature selectors map.
2549+
* @param string $feature_key The feature to look up (e.g. 'dimensions').
2550+
* @param string $default_selector Fallback selector.
2551+
* @return string The resolved selector.
2552+
*/
2553+
private static function get_feature_selector( array $feature_selectors, string $feature_key, string $default_selector ): string {
2554+
if ( ! isset( $feature_selectors[ $feature_key ] ) ) {
2555+
return $default_selector;
2556+
}
2557+
2558+
$feature = $feature_selectors[ $feature_key ];
2559+
2560+
if ( is_string( $feature ) ) {
2561+
return $feature;
2562+
}
2563+
2564+
if ( isset( $feature['root'] ) && is_string( $feature['root'] ) ) {
2565+
return $feature['root'];
2566+
}
2567+
2568+
return $default_selector;
2569+
}
2570+
24982571
/**
24992572
* Given a selector and a declaration list,
25002573
* creates the corresponding ruleset.
@@ -3145,8 +3218,9 @@ protected static function get_setting_nodes( $theme_json, $selectors = array() )
31453218
}
31463219

31473220
$nodes[] = array(
3148-
'path' => array( 'settings', 'blocks', $name ),
3149-
'selector' => $selector,
3221+
'path' => array( 'settings', 'blocks', $name ),
3222+
'selector' => $selector,
3223+
'selectors' => $selectors[ $name ]['selectors'] ?? array(),
31503224
);
31513225
}
31523226

src/wp-includes/rest-api/endpoints/class-wp-rest-abilities-v1-list-controller.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ public function get_item_schema(): array {
312312
),
313313
'additionalProperties' => true,
314314
),
315+
'public' => array(
316+
'description' => __( 'Whether the ability author intends the ability to be publicly available to clients. Only present when set by the ability author.' ),
317+
'type' => 'boolean',
318+
),
315319
),
316320
'context' => array( 'view', 'edit' ),
317321
'readonly' => true,

src/wp-includes/style-engine/class-wp-style-engine.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ final class WP_Style_Engine {
242242
'dimension' => '--wp--preset--dimension--$slug',
243243
),
244244
),
245+
'minWidth' => array(
246+
'property_keys' => array(
247+
'default' => 'min-width',
248+
),
249+
'path' => array( 'dimensions', 'minWidth' ),
250+
'css_vars' => array(
251+
'dimension' => '--wp--preset--dimension--$slug',
252+
),
253+
),
245254
'objectFit' => array(
246255
'property_keys' => array(
247256
'default' => 'object-fit',

tests/phpunit/tests/abilities-api/wpAbilitiesRegistry.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,6 @@ public function test_register_incorrect_output_schema_type() {
358358
$this->assertNull( $result );
359359
}
360360

361-
362361
/**
363362
* Should reject ability registration with invalid `annotations` type.
364363
*
@@ -410,6 +409,23 @@ public function test_register_invalid_show_in_rest_type() {
410409
$this->assertNull( $result );
411410
}
412411

412+
/**
413+
* Should reject ability registration with invalid public type.
414+
*
415+
* @ticket 65568
416+
*
417+
* @covers WP_Abilities_Registry::register
418+
* @covers WP_Ability::prepare_properties
419+
*
420+
* @expectedIncorrectUsage WP_Abilities_Registry::register
421+
*/
422+
public function test_register_invalid_public_type() {
423+
self::$test_ability_args['meta']['public'] = 5;
424+
425+
$result = $this->registry->register( self::$test_ability_name, self::$test_ability_args );
426+
$this->assertNull( $result );
427+
}
428+
413429
/**
414430
* Should reject registration for already registered ability.
415431
*

0 commit comments

Comments
 (0)