PluginProbe
Code Snippets / 4.0.0-beta.2
Code Snippets v4.0.0-beta.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
← All changes | php/Settings/settings.php +111 -22 3.10.04.0.0-beta.2 View file →
@@ -10,8 +10,9 @@
10 10 use Code_Snippets\Client\Welcome_Client;
11 11 use Code_Snippets\Controller\Cloud_Search_Controller;
12 12 use function add_action;
13 13 use function Code_Snippets\clean_snippets_cache;
14 +use function Code_Snippets\flush_versioned_cache_groups;
14 15 use function Code_Snippets\code_snippets;
15 16 use function Code_Snippets\Utils\add_self_option;
16 17 use function Code_Snippets\Utils\get_self_option;
17 18 use function Code_Snippets\Utils\update_self_option;
@@ -97,25 +98,80 @@
97 98 return update_self_option( are_settings_unified(), OPTION_NAME, $settings );
98 99 }
99 100
100 101 /**
102 + * Render the fields of a settings section, with group headings.
103 + *
104 + * Mirrors the core `do_settings_fields()`, adding a full-width heading row
105 + * above any field carrying a `group_heading` argument. Tabs are long enough
106 + * that unbroken rows are hard to scan.
107 + *
108 + * @param string $page Settings page slug.
109 + * @param string $section Settings section identifier.
110 + *
111 + * @return void
112 + */
113 +function do_settings_fields_with_headings( string $page, string $section ): void {
114 + global $wp_settings_fields;
115 +
116 + if ( ! isset( $wp_settings_fields[ $page ][ $section ] ) ) {
117 + return;
118 + }
119 +
120 + $seen_headings = [];
121 +
122 + foreach ( (array) $wp_settings_fields[ $page ][ $section ] as $field ) {
123 + $heading = $field['args']['group_heading'] ?? '';
124 +
125 + // A heading is skipped if an identical one has already been drawn, so
126 + // that a group whose first field is absent does not repeat it.
127 + if ( $heading && ! in_array( $heading, $seen_headings, true ) ) {
128 + $seen_headings[] = $heading;
129 + printf(
130 + '<tr class="settings-group-heading"><th colspan="2" scope="colgroup">%s</th></tr>',
131 + esc_html( $heading )
132 + );
133 + }
134 +
135 + $class = empty( $field['args']['class'] ) ? '' : ' class="' . esc_attr( $field['args']['class'] ) . '"';
136 +
137 + echo '<tr' . $class . '>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped above.
138 +
139 + // A field with no title, such as a notice rendered by a callback, spans
140 + // the row rather than leaving an empty header cell for a screen reader.
141 + if ( '' === (string) $field['title'] ) {
142 + echo '<td colspan="2">';
143 + call_user_func( $field['callback'], $field['args'] );
144 + echo '</td></tr>';
145 + continue;
146 + }
147 +
148 + if ( ! empty( $field['args']['label_for'] ) ) {
149 + printf(
150 + '<th scope="row"><label for="%s">%s</label></th>',
151 + esc_attr( $field['args']['label_for'] ),
152 + esc_html( $field['title'] )
153 + );
154 + } else {
155 + printf( '<th scope="row">%s</th>', esc_html( $field['title'] ) );
156 + }
157 +
158 + echo '<td>';
159 + call_user_func( $field['callback'], $field['args'] );
160 + echo '</td></tr>';
161 + }
162 +}
163 +
164 +/**
101 165 * Retrieve the settings sections
102 166 *
103 167 * @return array<string, string> Settings sections.
104 168 */
105 169 function get_settings_sections(): array {
106 - $sections = array(
107 - 'general' => __( 'General', 'code-snippets' ),
108 - 'editor' => __( 'Code Editor', 'code-snippets' ),
109 - 'debug' => __( 'Debug', 'code-snippets' ),
110 - );
170 + // Tabs are grouped by task rather than by storage section. Values still
171 + // save into their original sections; see Settings_Layout.
172 + $sections = Settings_Layout::get_available_tabs();
111 173
112 - // Only show the Version section when the debug setting to enable version changes is enabled.
113 - $enable_version = get_setting( 'debug', 'enable_version_change' );
114 - if ( $enable_version ) {
115 - $sections['version-switch'] = __( 'Version', 'code-snippets' );
116 - }
117 -
118 174 return apply_filters( 'code_snippets_settings_sections', $sections );
119 175 }
120 176
121 177 /**
@@ -139,22 +195,50 @@
139 195 foreach ( get_settings_sections() as $section_id => $section_name ) {
140 196 add_settings_section( $section_id, $section_name, '__return_empty_string', 'code-snippets' );
141 197 }
142 198
143 - // Register settings fields. Only register fields for sections that exist (some sections may be gated by settings).
144 - $registered_sections = get_settings_sections();
145 - foreach ( Settings_Fields::get_field_definitions() as $section_id => $fields ) {
146 - if ( ! isset( $registered_sections[ $section_id ] ) ) {
147 - continue;
148 - }
199 + // Register settings fields. The tab a field appears under comes from the
200 + // layout, while the section it saves into stays exactly as it was.
201 + $definitions = Settings_Fields::get_field_definitions();
202 + $descriptions = Settings_Layout::get_descriptions();
203 + $headings = Settings_Layout::get_group_headings();
149 204
150 - foreach ( $fields as $field_id => $field ) {
151 - if ( ! should_render_setting_field( $field, $current_settings ) ) {
152 - continue;
205 + foreach ( get_settings_sections() as $tab_id => $tab_name ) {
206 + foreach ( Settings_Layout::get_visible_fields( $tab_id, $current_settings ) as $entry ) {
207 + list( $section_id, $field_id ) = $entry;
208 + $field = $definitions[ $section_id ][ $field_id ];
209 +
210 + // Reword the settings whose description names the control without
211 + // saying what it buys you.
212 + if ( isset( $descriptions[ $field_id ] ) ) {
213 + $field['desc'] = $descriptions[ $field_id ];
153 214 }
154 215
155 216 $field_object = new Setting_Field( $section_id, $field_id, $field );
156 - add_settings_field( $field_id, $field['name'], [ $field_object, 'render' ], 'code-snippets', $section_id );
217 +
218 + // Field types that render a single labelable control get their table
219 + // heading turned into a real <label for>, giving the control an
220 + // accessible name. Checkboxes render their own labels, and
221 + // callback/action fields have no single control to point at.
222 + $labelable_types = [ 'text', 'number', 'select' ];
223 + $field_args = [];
224 +
225 + if ( isset( $field['type'] ) && in_array( $field['type'], $labelable_types, true ) ) {
226 + $field_args['label_for'] = $field_object->element_id;
227 + }
228 +
229 + if ( isset( $headings[ $tab_id ][ $field_id ] ) ) {
230 + $field_args['group_heading'] = $headings[ $tab_id ][ $field_id ];
231 + }
232 +
233 + add_settings_field(
234 + $field_id,
235 + $field['name'],
236 + [ $field_object, 'render' ],
237 + 'code-snippets',
238 + $tab_id,
239 + $field_args
240 + );
157 241 }
158 242 }
159 243
160 244 $editor_preview = new Editor_Preview();
@@ -164,9 +248,9 @@
164 248 'editor_preview',
165 249 __( 'Editor Preview', 'code-snippets' ),
166 250 [ $editor_preview, 'render' ],
167 251 'code-snippets',
168 - 'editor'
252 + 'editing'
169 253 );
170 254
171 255 Version_Switch::init();
172 256 }
@@ -310,8 +394,13 @@
310 394
311 395 if ( is_multisite() ) {
312 396 clean_snippets_cache( code_snippets()->db->get_table_name( true ) );
313 397 }
398 +
399 + // Deleting known keys cannot reach data written by a different version
400 + // of the plugin, which is what needs clearing before a rollback, so the
401 + // versioned groups (current, previous and legacy) all go too.
402 + flush_versioned_cache_groups( (string) get_option( 'code_snippets_cache_version', '' ) );
314 403
315 404 add_settings_error(
316 405 OPTION_NAME,
317 406 'snippet_caches_reset',