PluginProbe
Code Snippets / trunk
Code Snippets vtrunk
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/Admin/Menus/Settings_Menu.php +91 -36 4.0.0-beta.1 → trunk View file →
@@ -1,11 +1,13 @@
1 1 <?php
2 2
3 3 namespace Code_Snippets\Admin\Menus;
4 4
5 +use Code_Snippets\Admin\Contextual_Help;
5 6 use Code_Snippets\Settings\Settings_Fields;
6 7 use function Code_Snippets\code_snippets;
7 8 use function Code_Snippets\Settings\are_settings_unified;
9 +use function Code_Snippets\Settings\do_settings_fields_with_headings;
8 10 use function Code_Snippets\Utils\enqueue_code_editor;
9 11 use function Code_Snippets\Utils\get_editor_themes;
10 12 use const Code_Snippets\PLUGIN_FILE;
11 13 use const Code_Snippets\PLUGIN_VERSION;
@@ -13,11 +15,10 @@
13 15 use const Code_Snippets\Settings\OPTION_NAME;
14 16 use const Code_Snippets\Settings\CACHE_KEY;
15 17
16 18 /**
17 - * This class handles the settings admin menu
19 + * This class handles the settings admin menu.
18 20 *
19 - * @since 2.4.0
20 21 * @package Code_Snippets
21 22 */
22 23 class Settings_Menu extends Admin_Menu {
23 24
@@ -26,9 +27,9 @@
26 27 */
27 28 public const SETTINGS_PAGE = 'code-snippets';
28 29
29 30 /**
30 - * Constructor
31 + * Constructor.
31 32 */
32 33 public function __construct() {
33 34 parent::__construct(
34 35 'settings',
@@ -37,8 +38,37 @@
37 38 );
38 39 }
39 40
40 41 /**
42 + * Register the settings menu.
43 + *
44 + * Deliberately bypasses the snippet view-permission gate applied by the
45 + * parent. The settings page is already restricted to the core capability
46 + * (`manage_options` via `get_cap()`), so it stays admin-only regardless —
47 + * but it must always remain reachable so an administrator who restricts
48 + * their own role's snippet permissions can never lock themselves out of the
49 + * Permissions tab needed to undo it.
50 + */
51 + public function register() {
52 + $this->add_menu( $this->slug, $this->label, $this->title );
53 + }
54 +
55 + /**
56 + * The settings page is configuration territory (it includes the Permissions
57 + * tab itself), so it must remain restricted to full administrators — never
58 + * the broader snippet access capability that can be granted to other roles.
59 + * This is also what keeps an administrator from ever losing access to the
60 + * Permissions tab needed to undo a misconfiguration.
61 + *
62 + * @return string
63 + */
64 + protected function menu_cap(): string {
65 + return is_multisite() && ( is_network_admin() || ! code_snippets()->is_subsite_menu_enabled() )
66 + ? 'manage_network_options'
67 + : 'manage_options';
68 + }
69 +
70 + /**
41 71 * Executed when the admin page is loaded
42 72 */
43 73 public function load() {
44 74 parent::load();
@@ -50,8 +80,11 @@
50 80 wp_safe_redirect( code_snippets()->get_menu_url( 'settings', 'admin' ) );
51 81 exit;
52 82 }
53 83 }
84 +
85 + $contextual_help = new Contextual_Help( 'settings' );
86 + $contextual_help->load();
54 87 }
55 88
56 89 /**
57 90 * Enqueue the stylesheet for the settings menu
@@ -62,9 +95,9 @@
62 95
63 96 wp_enqueue_style(
64 97 $handle,
65 98 plugins_url( 'dist/settings.css', PLUGIN_FILE ),
66 - self::$style_deps + [ 'code-editor' ],
99 + array_merge( self::$style_deps, [ 'code-editor' ] ),
67 100 PLUGIN_VERSION
68 101 );
69 102
70 103 wp_enqueue_script(
@@ -69,9 +102,9 @@
69 102
70 103 wp_enqueue_script(
71 104 $handle,
72 105 plugins_url( 'dist/settings.js', PLUGIN_FILE ),
73 - self::$script_deps + [ 'code-snippets-code-editor' ],
106 + array_merge( self::$script_deps, [ 'code-snippets-code-editor' ] ),
74 107 PLUGIN_VERSION,
75 108 true
76 109 );
77 110
@@ -175,9 +208,9 @@
175 208 * @param string $default_section Name of the default tab displayed.
176 209 *
177 210 * @return string
178 211 */
179 - public function get_current_section( string $default_section = 'general' ): string {
212 + public function get_current_section( string $default_section = '' ): string {
180 213 $sections = $this->get_sections();
181 214
182 215 if ( ! $sections ) {
183 216 return $default_section;
@@ -182,11 +215,17 @@
182 215 if ( ! $sections ) {
183 216 return $default_section;
184 217 }
185 218
219 + // Fall back to the first registered tab. Naming a specific section here
220 + // meant the page rendered empty whenever that section stopped existing.
221 + $fallback = $default_section && isset( $sections[ $default_section ] )
222 + ? $default_section
223 + : (string) array_key_first( $sections );
224 +
186 225 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Value is matched to registered sections.
187 - $active_tab = isset( $_REQUEST['section'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['section'] ) ) : $default_section;
188 - return isset( $sections[ $active_tab ] ) ? $active_tab : $default_section;
226 + $active_tab = isset( $_REQUEST['section'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['section'] ) ) : $fallback;
227 + return isset( $sections[ $active_tab ] ) ? $active_tab : $fallback;
189 228 }
190 229
191 230 /**
192 231 * Render the admin screen
@@ -197,31 +236,37 @@
197 236 $update_url = is_network_admin() ? add_query_arg( 'update_site_option', true ) : admin_url( 'options.php' );
198 237 $current_section = $this->get_current_section();
199 238
200 239 ?>
201 - <div class="wrap" data-active-tab="<?php echo esc_attr( $current_section ); ?>">
202 - <h2>
203 - <?php
204 - esc_html_e( 'Settings', 'code-snippets' );
240 + <div class="wrap code-snippets-settings" data-active-tab="<?php echo esc_attr( $current_section ); ?>">
241 + <?php $this->render_section_tabs(); ?>
205 242
206 - if ( code_snippets()->is_compact_menu() ) {
207 - $actions = [
208 - _x( 'Manage', 'snippets', 'code-snippets' ) => code_snippets()->get_menu_url(),
209 - _x( 'Add New', 'snippet', 'code-snippets' ) => code_snippets()->get_menu_url( 'add' ),
210 - _X( 'Import', 'snippets', 'code-snippets' ) => code_snippets()->get_menu_url( 'import' ),
211 - ];
243 + <div class="snippets-page-header">
244 + <h1><?php esc_html_e( 'Snippets Settings', 'code-snippets' ); ?></h1>
245 + </div>
212 246
213 - foreach ( $actions as $label => $url ) {
214 - printf(
215 - '<a href="%s" class="page-title-action">%s</a>',
216 - esc_url( $url ),
217 - esc_html( $label )
218 - );
219 - }
247 + <?php
248 + if ( code_snippets()->is_compact_menu() ) {
249 + $actions = [
250 + _x( 'Manage', 'snippets', 'code-snippets' ) => code_snippets()->get_menu_url(),
251 + _x( 'Add New', 'snippet', 'code-snippets' ) => code_snippets()->get_menu_url( 'add' ),
252 + _x( 'Import', 'snippets', 'code-snippets' ) => code_snippets()->get_menu_url( 'import' ),
253 + ];
254 +
255 + echo '<p class="settings-page-actions">';
256 +
257 + foreach ( $actions as $label => $url ) {
258 + printf(
259 + '<a href="%s" class="page-title-action">%s</a>',
260 + esc_url( $url ),
261 + esc_html( $label )
262 + );
220 263 }
221 - ?>
222 - </h2>
223 264
265 + echo '</p>';
266 + }
267 + ?>
268 +
224 269 <hr class="wp-header-end" />
225 270
226 271 <?php settings_errors( OPTION_NAME ); ?>
227 272
@@ -229,9 +274,9 @@
229 274 <input type="hidden" name="section" value="<?php echo esc_attr( $current_section ); ?>">
230 275 <?php
231 276
232 277 settings_fields( OPTION_GROUP );
233 - $this->do_settings_tabs();
278 + $this->render_settings_sections();
234 279 ?>
235 280 <p class="submit">
236 281 <?php
237 282 submit_button( null, 'primary', 'submit', false );
@@ -249,20 +294,22 @@
249 294 <?php
250 295 }
251 296
252 297 /**
253 - * Output snippet settings in tabs
298 + * Output the settings section subnavigation bar, styled to match the
299 + * subnavigation on the snippet management pages, followed by the slot
300 + * that adopts the Screen Options and Help tabs.
254 301 */
255 - protected function do_settings_tabs() {
302 + protected function render_section_tabs() {
256 303 $sections = $this->get_sections();
257 304 $active_tab = $this->get_current_section();
258 305
259 - echo '<nav class="nav-tab-wrapper" id="settings-sections-tabs" aria-label="' . esc_attr__( 'Settings tabs', 'code-snippets' ) . '">';
306 + echo '<div class="snippet-type-nav-wrapper settings-type-nav-wrapper"><nav class="snippet-type-nav settings-type-nav" id="settings-sections-tabs" aria-label="' . esc_attr__( 'Settings tabs', 'code-snippets' ) . '"><ul>';
260 307
261 308 foreach ( $sections as $section ) {
262 309 printf(
263 - '<a class="nav-tab%s" data-section="%s" href="%s">%s</a>',
264 - esc_attr( $active_tab ) === $section['id'] ? ' nav-tab-active' : '',
310 + '<li><a class="snippet-type-link%s" data-section="%s" href="%s"><span>%s</span></a></li>',
311 + esc_attr( $active_tab ) === $section['id'] ? ' active-type' : '',
265 312 esc_attr( $section['id'] ),
266 313 esc_url( add_query_arg( 'section', $section['id'] ) ),
267 314 esc_html( $section['title'] )
268 315 );
@@ -267,10 +314,18 @@
267 314 esc_html( $section['title'] )
268 315 );
269 316 }
270 317
271 - echo '</nav>';
318 + echo '</ul></nav></div>';
319 + echo '<div id="snippets-screen-meta-slot" class="snippets-screen-meta-slot"></div>';
320 + }
272 321
322 + /**
323 + * Output snippet settings sections.
324 + */
325 + protected function render_settings_sections() {
326 + $sections = $this->get_sections();
327 +
273 328 foreach ( $sections as $section ) {
274 329 if ( 'license' === $section['id'] ) {
275 330 continue;
276 331 }
@@ -276,9 +331,9 @@
276 331 }
277 332
278 333 if ( $section['title'] ) {
279 334 printf(
280 - '<h3 id="%s-settings" class="settings-section-title">%s</h3>' . "\n",
335 + '<h2 id="%s-settings" class="settings-section-title">%s</h2>' . "\n",
281 336 esc_attr( $section['id'] ),
282 337 esc_html( $section['title'] )
283 338 );
284 339 }
@@ -288,9 +343,9 @@
288 343 }
289 344
290 345 printf( '<div class="settings-section %s-settings"><table class="form-table">', esc_attr( $section['id'] ) );
291 346
292 - do_settings_fields( self::SETTINGS_PAGE, $section['id'] );
347 + do_settings_fields_with_headings( self::SETTINGS_PAGE, $section['id'] );
293 348 echo '</table></div>';
294 349 }
295 350 }
296 351