Skip to content

Commit bdfd433

Browse files
Abilities API: Add core/get-settings ability.
Introduce a new `core/get-settings` ability to the WordPress Abilities API that dynamically discovers and exposes WordPress settings. Settings with `show_in_abilities` enabled are exposed through this ability. Props jorgefilipecosta, jason_the_adams, mukeshpanchal27, justlevine, ovidiu-galatan. Fixes #64605. git-svn-id: https://develop.svn.wordpress.org/trunk@61600 602fd350-edb4-49c9-b593-d223f7449a82
1 parent b2486b8 commit bdfd433

4 files changed

Lines changed: 797 additions & 73 deletions

File tree

src/wp-includes/abilities.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
declare( strict_types = 1 );
1111

12+
require_once __DIR__ . '/abilities/class-wp-settings-abilities.php';
13+
1214
/**
1315
* Registers the core ability categories.
1416
*
@@ -257,4 +259,6 @@ function wp_register_core_abilities(): void {
257259
),
258260
)
259261
);
262+
263+
WP_Settings_Abilities::register();
260264
}
Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
<?php
2+
/**
3+
* Registers core settings abilities.
4+
*
5+
* This is a utility class to encapsulate the registration of settings-related abilities.
6+
* It is not intended to be instantiated or consumed directly by any other code or plugin.
7+
*
8+
* @package WordPress
9+
* @subpackage Abilities_API
10+
* @since 7.0.0
11+
*
12+
* @internal This class is not part of the public API.
13+
* @access private
14+
*/
15+
16+
declare( strict_types=1 );
17+
18+
/**
19+
* Registers core settings abilities.
20+
*
21+
* @since 7.0.0
22+
* @access private
23+
*/
24+
class WP_Settings_Abilities {
25+
26+
/**
27+
* Available setting groups with show_in_abilities enabled.
28+
*
29+
* @since 7.0.0
30+
* @var string[]
31+
*/
32+
private static $available_groups;
33+
34+
/**
35+
* Dynamic output schema built from registered settings.
36+
*
37+
* @since 7.0.0
38+
* @var array
39+
*/
40+
private static $output_schema;
41+
42+
/**
43+
* Available setting slugs with show_in_abilities enabled.
44+
*
45+
* @since 7.0.0
46+
* @var string[]
47+
*/
48+
private static $available_slugs;
49+
50+
/**
51+
* Registers all settings abilities.
52+
*
53+
* @since 7.0.0
54+
*
55+
* @return void
56+
*/
57+
public static function register(): void {
58+
self::init();
59+
self::register_get_settings();
60+
}
61+
62+
/**
63+
* Initializes shared data for settings abilities.
64+
*
65+
* @since 7.0.0
66+
*
67+
* @return void
68+
*/
69+
private static function init(): void {
70+
self::$available_groups = self::get_available_groups();
71+
self::$available_slugs = self::get_available_slugs();
72+
self::$output_schema = self::build_output_schema();
73+
}
74+
75+
/**
76+
* Gets registered settings that have show_in_abilities enabled.
77+
*
78+
* @since 7.0.0
79+
*
80+
* @return array Associative array of option_name => args for allowed settings.
81+
*/
82+
private static function get_allowed_settings(): array {
83+
$settings = array();
84+
85+
foreach ( get_registered_settings() as $option_name => $args ) {
86+
if ( ! empty( $args['show_in_abilities'] ) ) {
87+
$settings[ $option_name ] = $args;
88+
}
89+
}
90+
91+
return $settings;
92+
}
93+
94+
/**
95+
* Gets unique setting groups that have show_in_abilities enabled.
96+
*
97+
* @since 7.0.0
98+
*
99+
* @return string[] List of unique group names.
100+
*/
101+
private static function get_available_groups(): array {
102+
$groups = array();
103+
104+
foreach ( self::get_allowed_settings() as $args ) {
105+
$group = $args['group'] ?? 'general';
106+
if ( ! in_array( $group, $groups, true ) ) {
107+
$groups[] = $group;
108+
}
109+
}
110+
111+
sort( $groups );
112+
113+
return $groups;
114+
}
115+
116+
/**
117+
* Gets unique setting slugs that have show_in_abilities enabled.
118+
*
119+
* @since 7.0.0
120+
*
121+
* @return string[] List of unique setting slugs.
122+
*/
123+
private static function get_available_slugs(): array {
124+
$slugs = array();
125+
126+
foreach ( self::get_allowed_settings() as $option_name => $args ) {
127+
$slugs[] = $option_name;
128+
}
129+
130+
sort( $slugs );
131+
132+
return $slugs;
133+
}
134+
135+
/**
136+
* Builds a rich output schema from registered settings metadata.
137+
*
138+
* Creates a JSON Schema that documents each setting group and its settings
139+
* with their types, titles, descriptions, defaults, and any additional
140+
* schema properties from show_in_rest.
141+
*
142+
* @since 7.0.0
143+
*
144+
* @return array JSON Schema for the output.
145+
*/
146+
private static function build_output_schema(): array {
147+
$group_properties = array();
148+
149+
foreach ( self::get_allowed_settings() as $option_name => $args ) {
150+
$group = $args['group'] ?? 'general';
151+
152+
$setting_schema = array(
153+
'type' => $args['type'] ?? 'string',
154+
);
155+
156+
if ( ! empty( $args['label'] ) ) {
157+
$setting_schema['title'] = $args['label'];
158+
}
159+
160+
if ( ! empty( $args['description'] ) ) {
161+
$setting_schema['description'] = $args['description'];
162+
} elseif ( ! empty( $args['label'] ) ) {
163+
$setting_schema['description'] = $args['label'];
164+
}
165+
166+
if ( ! isset( $group_properties[ $group ] ) ) {
167+
$group_properties[ $group ] = array(
168+
'type' => 'object',
169+
'properties' => array(),
170+
'additionalProperties' => false,
171+
);
172+
}
173+
174+
$group_properties[ $group ]['properties'][ $option_name ] = $setting_schema;
175+
}
176+
177+
ksort( $group_properties );
178+
179+
return array(
180+
'type' => 'object',
181+
'description' => __( 'Settings grouped by registration group. Each group contains settings with their current values.' ),
182+
'properties' => $group_properties,
183+
'additionalProperties' => false,
184+
);
185+
}
186+
187+
/**
188+
* Registers the core/get-settings ability.
189+
*
190+
* @since 7.0.0
191+
*
192+
* @return void
193+
*/
194+
private static function register_get_settings(): void {
195+
wp_register_ability(
196+
'core/get-settings',
197+
array(
198+
'label' => __( 'Get Settings' ),
199+
'description' => __( 'Returns registered WordPress settings grouped by their registration group. Returns key-value pairs per setting.' ),
200+
'category' => 'site',
201+
'input_schema' => array(
202+
'default' => (object) array(),
203+
'oneOf' => array(
204+
// Branch 1: No filter (empty object).
205+
array(
206+
'type' => 'object',
207+
'additionalProperties' => false,
208+
'maxProperties' => 0,
209+
),
210+
// Branch 2: Filter by group only.
211+
array(
212+
'type' => 'object',
213+
'properties' => array(
214+
'group' => array(
215+
'type' => 'string',
216+
'description' => __( 'Filter settings by group name.' ),
217+
'enum' => self::$available_groups,
218+
),
219+
),
220+
'required' => array( 'group' ),
221+
'additionalProperties' => false,
222+
),
223+
// Branch 3: Filter by slugs only.
224+
array(
225+
'type' => 'object',
226+
'properties' => array(
227+
'slugs' => array(
228+
'type' => 'array',
229+
'description' => __( 'Filter settings by specific setting slugs.' ),
230+
'items' => array(
231+
'type' => 'string',
232+
'enum' => self::$available_slugs,
233+
),
234+
),
235+
),
236+
'required' => array( 'slugs' ),
237+
'additionalProperties' => false,
238+
),
239+
),
240+
),
241+
'output_schema' => self::$output_schema,
242+
'execute_callback' => array( __CLASS__, 'execute_get_settings' ),
243+
'permission_callback' => array( __CLASS__, 'check_manage_options' ),
244+
'meta' => array(
245+
'annotations' => array(
246+
'readonly' => true,
247+
'destructive' => false,
248+
'idempotent' => true,
249+
),
250+
'show_in_rest' => true,
251+
),
252+
)
253+
);
254+
}
255+
256+
/**
257+
* Permission callback for settings abilities.
258+
*
259+
* @since 7.0.0
260+
*
261+
* @return bool True if the current user can manage options, false otherwise.
262+
*/
263+
public static function check_manage_options(): bool {
264+
return current_user_can( 'manage_options' );
265+
}
266+
267+
/**
268+
* Execute callback for core/get-settings ability.
269+
*
270+
* Retrieves all registered settings that are exposed through the Abilities API,
271+
* grouped by their registration group.
272+
*
273+
* @since 7.0.0
274+
*
275+
* @param array $input {
276+
* Optional. Input parameters.
277+
*
278+
* @type string $group Optional. Filter settings by group name. Cannot be used with slugs.
279+
* @type string[] $slugs Optional. Filter settings by specific setting slugs. Cannot be used with group.
280+
* }
281+
* @return array Settings grouped by registration group.
282+
*/
283+
public static function execute_get_settings( $input = array() ): array {
284+
$input = is_array( $input ) ? $input : array();
285+
$filter_group = ! empty( $input['group'] ) ? $input['group'] : null;
286+
$filter_slugs = ! empty( $input['slugs'] ) ? $input['slugs'] : null;
287+
288+
$settings_by_group = array();
289+
290+
foreach ( self::get_allowed_settings() as $option_name => $args ) {
291+
$group = $args['group'] ?? 'general';
292+
293+
if ( $filter_group && $group !== $filter_group ) {
294+
continue;
295+
}
296+
297+
if ( $filter_slugs && ! in_array( $option_name, $filter_slugs, true ) ) {
298+
continue;
299+
}
300+
301+
$default = $args['default'] ?? null;
302+
303+
$value = get_option( $option_name, $default );
304+
$value = self::cast_value( $value, $args['type'] ?? 'string' );
305+
306+
if ( ! isset( $settings_by_group[ $group ] ) ) {
307+
$settings_by_group[ $group ] = array();
308+
}
309+
310+
$settings_by_group[ $group ][ $option_name ] = $value;
311+
}
312+
313+
ksort( $settings_by_group );
314+
315+
return $settings_by_group;
316+
}
317+
318+
/**
319+
* Casts a value to the appropriate type based on the setting's registered type.
320+
*
321+
* @since 7.0.0
322+
*
323+
* @param mixed $value The value to cast.
324+
* @param string $type The registered type (string, boolean, integer, number, array, object).
325+
* @return string|bool|int|float|array The cast value.
326+
*/
327+
private static function cast_value( $value, string $type ) {
328+
switch ( $type ) {
329+
case 'boolean':
330+
return (bool) $value;
331+
case 'integer':
332+
return (int) $value;
333+
case 'number':
334+
return (float) $value;
335+
case 'array':
336+
case 'object':
337+
return is_array( $value ) ? $value : array();
338+
case 'string':
339+
default:
340+
return (string) $value;
341+
}
342+
}
343+
}

0 commit comments

Comments
 (0)