Skip to content

Commit aa6409b

Browse files
dkotterjorgefilipecostadkotterjeffpaul
authored
Merge pull request #376 from WordPress/feature/settings-toggle-autosave
Use toggle UI, auto-save, and inline DataForm settings for experiments Co-authored-by: jorgefilipecosta <jorgefilipecosta@git.wordpress.org> Co-authored-by: dkotter <dkotter@git.wordpress.org> Co-authored-by: jeffpaul <jeffpaul@git.wordpress.org>
2 parents afc7cb4 + e0bddc2 commit aa6409b

12 files changed

Lines changed: 872 additions & 195 deletions

File tree

includes/Abstracts/Abstract_Feature.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,55 @@ public function register_settings(): void {
216216
// Child classes can override to register custom settings.
217217
}
218218

219+
/**
220+
* Gets the field definitions for feature-specific settings.
221+
*
222+
* Override this method in child classes to declare custom settings fields
223+
* that will be rendered as a DataForm on the settings page. Each field
224+
* should use the short option name (e.g. 'strategy'), not the full
225+
* namespaced option name.
226+
*
227+
* @since x.x.x
228+
*
229+
* @return array<int, array{
230+
* id: string,
231+
* label: string,
232+
* type: string,
233+
* default?: mixed,
234+
* elements?: list<array{value: string, label: string}>,
235+
* isValid?: array{min?: int, max?: int},
236+
* }> Array of field definitions matching the DataForm Field shape.
237+
*/
238+
public function get_settings_fields(): array {
239+
return array();
240+
}
241+
242+
/**
243+
* Gets field definitions with fully resolved option names.
244+
*
245+
* Transforms the short field IDs from get_settings_fields() into
246+
* full WordPress option names suitable for the REST API and frontend.
247+
*
248+
* @since x.x.x
249+
*
250+
* @return array<int, array{
251+
* id: string,
252+
* label: string,
253+
* type: string,
254+
* default?: mixed,
255+
* elements?: list<array{value: string, label: string}>,
256+
* isValid?: array{min?: int, max?: int},
257+
* }> Array of field definitions with full option names.
258+
*/
259+
public function get_settings_fields_metadata(): array {
260+
$fields = $this->get_settings_fields();
261+
foreach ( $fields as &$field ) {
262+
$field['id'] = $this->get_field_option_name( $field['id'] );
263+
}
264+
unset( $field );
265+
return $fields;
266+
}
267+
219268
/**
220269
* Gets the option name for a custom feature setting field.
221270
*

includes/Contracts/Feature.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,22 @@ public function register(): void;
8888
* @return bool True if enabled, false otherwise.
8989
*/
9090
public function is_enabled(): bool;
91+
92+
/**
93+
* Gets field definitions with fully resolved option names.
94+
*
95+
* Returns an empty array when the feature has no custom settings.
96+
*
97+
* @since x.x.x
98+
*
99+
* @return array<int, array{
100+
* id: string,
101+
* label: string,
102+
* type: string,
103+
* default?: mixed,
104+
* elements?: list<array{value: string, label: string}>,
105+
* isValid?: array{min?: int, max?: int},
106+
* }> Array of field definitions with full option names.
107+
*/
108+
public function get_settings_fields_metadata(): array;
91109
}

includes/Experiments/Content_Classification/Content_Classification.php

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,24 @@ class Content_Classification extends Abstract_Feature {
5656
*/
5757
public const DEFAULT_MAX_SUGGESTIONS = 5;
5858

59+
/**
60+
* The minimum allowed number of suggestions.
61+
*
62+
* @since x.x.x
63+
*
64+
* @var int
65+
*/
66+
public const MIN_SUGGESTIONS = 1;
67+
68+
/**
69+
* The maximum allowed number of suggestions.
70+
*
71+
* @since x.x.x
72+
*
73+
* @var int
74+
*/
75+
public const MAX_SUGGESTIONS = 10;
76+
5977
/**
6078
* {@inheritDoc}
6179
*/
@@ -153,6 +171,12 @@ public function register_settings(): void {
153171
'type' => 'string',
154172
'default' => self::STRATEGY_EXISTING_ONLY,
155173
'sanitize_callback' => array( $this, 'sanitize_strategy' ),
174+
'show_in_rest' => array(
175+
'schema' => array(
176+
'type' => 'string',
177+
'enum' => array( self::STRATEGY_EXISTING_ONLY, self::STRATEGY_ALLOW_NEW ),
178+
),
179+
),
156180
)
157181
);
158182

@@ -163,65 +187,49 @@ public function register_settings(): void {
163187
'type' => 'integer',
164188
'default' => self::DEFAULT_MAX_SUGGESTIONS,
165189
'sanitize_callback' => array( $this, 'sanitize_max_suggestions' ),
190+
'show_in_rest' => array(
191+
'schema' => array(
192+
'type' => 'integer',
193+
'minimum' => self::MIN_SUGGESTIONS,
194+
'maximum' => self::MAX_SUGGESTIONS,
195+
),
196+
),
166197
)
167198
);
168199
}
169200

170201
/**
171-
* Renders experiment-specific settings fields.
172-
*
173-
* @since x.x.x
202+
* {@inheritDoc}
174203
*/
175-
public function render_settings_fields(): void {
176-
$strategy_option = $this->get_field_option_name( 'strategy' );
177-
$max_suggestions_option = $this->get_field_option_name( 'max_suggestions' );
178-
$current_strategy = get_option( $this->get_field_option_name( 'strategy' ), self::STRATEGY_EXISTING_ONLY );
179-
$current_max = get_option( $this->get_field_option_name( 'max_suggestions' ), self::DEFAULT_MAX_SUGGESTIONS );
180-
?>
181-
<fieldset class="ai-experiments__item-fields">
182-
<legend class="screen-reader-text"><?php esc_html_e( 'Content Classification Settings', 'ai' ); ?></legend>
183-
<table class="ai-experiments__settings-table" role="presentation">
184-
<tr>
185-
<td>
186-
<label for="<?php echo esc_attr( $strategy_option ); ?>">
187-
<?php esc_html_e( 'Taxonomy strategy:', 'ai' ); ?>
188-
</label>
189-
</td>
190-
<td>
191-
<select
192-
id="<?php echo esc_attr( $strategy_option ); ?>"
193-
name="<?php echo esc_attr( $strategy_option ); ?>"
194-
>
195-
<option value="<?php echo esc_attr( self::STRATEGY_EXISTING_ONLY ); ?>" <?php selected( $current_strategy, self::STRATEGY_EXISTING_ONLY ); ?>>
196-
<?php esc_html_e( 'Only suggest existing terms', 'ai' ); ?>
197-
</option>
198-
<option value="<?php echo esc_attr( self::STRATEGY_ALLOW_NEW ); ?>" <?php selected( $current_strategy, self::STRATEGY_ALLOW_NEW ); ?>>
199-
<?php esc_html_e( 'Suggest new terms based on context', 'ai' ); ?>
200-
</option>
201-
</select>
202-
</td>
203-
</tr>
204-
<tr>
205-
<td>
206-
<label for="<?php echo esc_attr( $max_suggestions_option ); ?>">
207-
<?php esc_html_e( 'Maximum suggestions:', 'ai' ); ?>
208-
</label>
209-
</td>
210-
<td>
211-
<input
212-
type="number"
213-
id="<?php echo esc_attr( $max_suggestions_option ); ?>"
214-
name="<?php echo esc_attr( $max_suggestions_option ); ?>"
215-
value="<?php echo esc_attr( (string) $current_max ); ?>"
216-
min="1"
217-
max="10"
218-
step="1"
219-
/>
220-
</td>
221-
</tr>
222-
</table>
223-
</fieldset>
224-
<?php
204+
public function get_settings_fields(): array {
205+
return array(
206+
array(
207+
'id' => 'strategy',
208+
'label' => __( 'Taxonomy strategy', 'ai' ),
209+
'type' => 'text',
210+
'default' => self::STRATEGY_EXISTING_ONLY,
211+
'elements' => array(
212+
array(
213+
'value' => self::STRATEGY_EXISTING_ONLY,
214+
'label' => __( 'Only suggest existing terms', 'ai' ),
215+
),
216+
array(
217+
'value' => self::STRATEGY_ALLOW_NEW,
218+
'label' => __( 'Suggest new terms based on context', 'ai' ),
219+
),
220+
),
221+
),
222+
array(
223+
'id' => 'max_suggestions',
224+
'label' => __( 'Maximum suggestions', 'ai' ),
225+
'type' => 'integer',
226+
'default' => self::DEFAULT_MAX_SUGGESTIONS,
227+
'isValid' => array(
228+
'min' => self::MIN_SUGGESTIONS,
229+
'max' => self::MAX_SUGGESTIONS,
230+
),
231+
),
232+
);
225233
}
226234

227235
/**
@@ -249,7 +257,7 @@ public function sanitize_strategy( $value ): string {
249257
public function sanitize_max_suggestions( $value ): int {
250258
$value = absint( $value );
251259

252-
return max( 1, min( 10, $value ) );
260+
return max( self::MIN_SUGGESTIONS, min( self::MAX_SUGGESTIONS, $value ) );
253261
}
254262

255263
/**

includes/bootstrap.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,12 @@ function get_settings_feature_metadata( Registry $registry ): array {
226226

227227
$categories_in_use[ $category ] = true;
228228
$features[] = array(
229-
'id' => $feature_id,
230-
'settingName' => "wpai_feature_{$feature_id}_enabled",
231-
'label' => $feature->get_label(),
232-
'description' => wp_strip_all_tags( $feature->get_description() ),
233-
'category' => $category,
229+
'id' => $feature_id,
230+
'settingName' => "wpai_feature_{$feature_id}_enabled",
231+
'label' => $feature->get_label(),
232+
'description' => wp_strip_all_tags( $feature->get_description() ),
233+
'category' => $category,
234+
'settingsFields' => $feature->get_settings_fields_metadata(),
234235
);
235236
}
236237

0 commit comments

Comments
 (0)