
edit-theme-options user capability
‘edit_theme_options’ capability seems to be self-explained. It’s primary purpose is to provide access to WordPress front-end theme options changing.
On practice, if you have ‘edit_theme_options’ capability, then you have access to the ‘Appearance’ menu at WordPress admin back-end and to its menu items: “Themes” (select a theme for your WordPress front-end) and “Menus” (edit menus supported by your selected theme). Customize theme header image, background color, etc. section and ‘Widgets’ menu items require ‘edit_theme_options’ capability also.
How it is realized? How often and at what places WordPress uses/checks this user capability – ‘edit_theme_options’ in order to decide give current user permission to edit theme options or prohibit access to such functionality? Let’s check this together. We will make a quick look into WordPress version 3.4.2 core source code and comment its related fragments.
Simple search through WordPress source code subdirectories for ‘edit_theme_options’ keyword shows, that WordPress uses ‘edit_theme_options’ capability in 21 files.
Files with ‘edit_theme_options’ capability inside
- wp-admin/admin-header.php,
- wp-admin/custom-background.php,
- wp-admin/custom-header.php,
- wp-admin/customize.php,
- wp-admin/includes/ajax-actions.php,
- wp-admin/includes/class-wp-themes-list-table.php,
- wp-admin/includes/dashboard.php,
- wp-admin/includes/schema.php,
- wp-admin/includes/screen.php,
- wp-admin/includes/template.php,
- wp-admin/index.php,
- wp-admin/menu.php,
- wp-admin/nav-menus.php,
- wp-admin/themes.php,
- wp-admin/widgets.php,
- wp-content/themes/twentyeleven/inc/theme-options.php,
- wp-includes/admin-bar.php,
- wp-includes/class-wp-customize-manager.php,
- wp-includes/class-wp-customize-section.php,
- wp-includes/class-wp-customize-setting.php,
- wp-includes/functions.php
wp-admin/admin-header.php
This is technological permission check before apply customize body classes. There is nothing occur here in concern to the user interface and user access to WordPress functionality.
103 104 105 106 | // If the customize-loader script is enqueued, make sure the customize // body classes are correct as early as possible. if ( wp_script_is( 'customize-loader', 'queue' ) && current_user_can( 'edit_theme_options' ) ) wp_customize_support_script(); |
wp_customize_support_script()
function is located at the wp-includes/theme.php file and has such comments:
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 | /** * Prints a script to check whether or not the customizer is supported, * and apply either the no-customize-support or customize-support class * to the body. * * This function MUST be called inside the body tag. * * Ideally, call this function immediately after the body tag is opened. * This prevents a flash of unstyled content. * * It is also recommended that you add the "no-customize-support" class * to the body tag by default. * * @since 3.4.0 */ function wp_customize_support_script() { |
wp-admin/custom-background.php
This is the custom background script. ‘edit_theme_options’ capability is located here in this file:
61 62 63 64 65 66 67 68 69 70 | /** * Set up the hooks for the Custom Background admin page. * * @since 3.0.0 */ function init() { if ( ! current_user_can('edit_theme_options') ) return; $this->page = $page = add_theme_page(__('Background'), __('Background'), 'edit_theme_options', 'custom-background', array(&$this, 'admin_page')); |
Thus, if user has correspondent permission, he will see ‘Background’ menu item at the ‘Appearance’ menu and will be able to setup custom background image and select background color for the selected theme.
We see ‘edit_theme_options’ capability second time almost at the end of file:
417 418 | public function wp_set_background_image() { if ( ! current_user_can('edit_theme_options') || ! isset( $_POST['attachment_id'] ) ) exit; |
It’s additional check of user permission before process of image upload and replace theme background image.
wp-admin/custom-header.php
This is the custom header image script. According to the init()
function code below
78 79 80 81 82 83 84 85 86 87 | /** * Set up the hooks for the Custom Header admin page. * * @since 2.1.0 */ function init() { if ( ! current_user_can('edit_theme_options') ) return; $this->page = $page = add_theme_page(__('Header'), __('Header'), 'edit_theme_options', 'custom-header', array(&$this, 'admin_page')); |
Only user with ‘edit_theme_options’ capability will see the ‘Header’ menu item at the ‘Appearance’ menu and be capable to change image header for the selected theme.
Second time this script uses ‘edit_theme_options’ capability before proceed with real change of the theme header image:
198 199 200 201 202 203 204 205 | /** * Execute custom header modification. * * @since 2.6.0 */ function take_action() { if ( ! current_user_can('edit_theme_options') ) return; |
Additionally custom-header.php
script checks discussed user permission to prevent possible hacker intervention in the middle of the multi-step theme header image change process:
915 916 917 918 919 920 921 922 | /** * Display the page based on the current step. * * @since 2.1.0 */ function admin_page() { if ( ! current_user_can('edit_theme_options') ) wp_die(__('You do not have permission to customize headers.')); |
wp-admin/customize.php
This is the Customize Controls script. It checks ‘edit_theme_options’ permission at very begin and stops execution if current user has no such capability:
13 14 | if ( ! current_user_can( 'edit_theme_options' ) ) wp_die( __( 'Cheatin’ uh?' ) ); |
wp-admin/includes/ajax-actions.php
This is WordPress Core Ajax Handlers script. It checks if current user has ‘edit_theme_options’ capability before proceed with adding of new menu item:
851 852 853 854 855 | function wp_ajax_add_menu_item() { check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' ); if ( ! current_user_can( 'edit_theme_options' ) ) wp_die( -1 ); |
That was interesting for me to discover that in order to hide ‘Welcome panel’ shown after WordPress core install or update, you need to have ‘edit_theme_options’ capability. But see the code below:
1183 1184 1185 1186 1187 1188 1189 | function wp_ajax_update_welcome_panel() { check_ajax_referer( 'welcome-panel-nonce', 'welcomepanelnonce' ); if ( ! current_user_can( 'edit_theme_options' ) ) wp_die( -1 ); update_user_meta( get_current_user_id(), 'show_welcome_panel', empty( $_POST['visible'] ) ? 0 : 1 ); |
Some functionality concerning menu metaboxes construction and editing via AJAX is also available if user has ‘edit_theme_options’ capability only:
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 | function wp_ajax_menu_get_metabox() { if ( ! current_user_can( 'edit_theme_options' ) ) wp_die( -1 ); require_once ABSPATH . 'wp-admin/includes/nav-menu.php'; if ( isset( $_POST['item-type'] ) && 'post_type' == $_POST['item-type'] ) { $type = 'posttype'; $callback = 'wp_nav_menu_item_post_type_meta_box'; $items = (array) get_post_types( array( 'show_in_nav_menus' => true ), 'object' ); } elseif ( isset( $_POST['item-type'] ) && 'taxonomy' == $_POST['item-type'] ) { $type = 'taxonomy'; $callback = 'wp_nav_menu_item_taxonomy_meta_box'; $items = (array) get_taxonomies( array( 'show_ui' => true ), 'object' ); } |
You can save menu changes if you have ‘edit_theme_options’ capability:
1255 1256 1257 1258 1259 1260 1261 1262 1263 | function wp_ajax_menu_locations_save() { if ( ! current_user_can( 'edit_theme_options' ) ) wp_die( -1 ); check_ajax_referer( 'add-menu_item', 'menu-settings-column-nonce' ); if ( ! isset( $_POST['menu-locations'] ) ) wp_die( 0 ); set_theme_mod( 'nav_menu_locations', array_map( 'absint', $_POST['menu-locations'] ) ); wp_die( 1 ); } |
You can make quick search in the menu via AJAX just if you have ‘edit_theme_options’ capability:
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 | function wp_ajax_menu_quick_search() { if ( ! current_user_can( 'edit_theme_options' ) ) wp_die( -1 ); require_once ABSPATH . 'wp-admin/includes/nav-menu.php'; _wp_ajax_menu_quick_search( $_POST ); wp_die(); } |
Widgets ordering is available to the user with ‘edit_theme_options’ capability only:
1492 1493 1494 1495 1496 | function wp_ajax_widgets_order() { check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' ); if ( !current_user_can('edit_theme_options') ) wp_die( -1 ); |
It is impossible to save changes made to the widget without ‘edit_theme_options’ capability too:
1523 1524 1525 1526 1527 1528 1529 | function wp_ajax_save_widget() { global $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates; check_ajax_referer( 'save-sidebar-widgets', 'savewidgets' ); if ( !current_user_can('edit_theme_options') || !isset($_POST['id_base']) ) wp_die( -1 ); |
wp-admin/includes/class-wp-themes-list-table.php
This is Themes List Table class. 1st time we meet ‘edit_theme_options’ capability at line #141 of display_rows()
function:
141 142 143 | if ( current_user_can( 'edit_theme_options' ) ) $actions['preview'] .= '<a href="' . wp_customize_url( $stylesheet ) . '" class="load-customize hide-if-no-customize">' . __( 'Live Preview' ) . '</a>'; |
This code ads ‘Live Preview’ action link to the available theme in case user has ‘edit_theme_options’ capability.
wp-admin/includes/dashboard.php
This file contains WordPress Dashboard Widget Administration Screen API. At line #382 WordPress builds text with title of active theme and quant of active widgets configured for it. WordPress shows this title at ‘Right Now’ widget. If user has ‘edit_theme_options’ capability, then text contains links to the widgets area and switch themes area:
382 383 384 385 386 | if ( current_user_can( 'edit_theme_options' ) ) { printf(_n('Theme <span class="b">%1$s</span> with <span class="b"><a href="widgets.php">%2$s Widget</a></span>', 'Theme <span class="b">%1$s</span> with <span class="b"><a href="widgets.php">%2$s Widgets</a></span>', $num_widgets), $switch_themes, $num); } else { printf(_n('Theme <span class="b">%1$s</span> with <span class="b">%2$s Widget</span>', 'Theme <span class="b">%1$s</span> with <span class="b">%2$s Widgets</span>', $num_widgets), $switch_themes, $num); } |
That’s interesting to discover that WordPress shows its ‘Welcome’ screen to the users with ‘edit_theme_options’ capability only:
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 | /** * Displays a welcome panel to introduce users to WordPress. * * @since 3.3.0 */ function wp_welcome_panel() { global $wp_version; if ( ! current_user_can( 'edit_theme_options' ) ) return; |
wp-admin/includes/schema.php
This is WordPress Administration Scheme API, where developers keep the DB structure and option values. From this file we know that ‘edit_theme_options’ capability was introduced with WordPress version 3.0:
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 | /** * Create and modify WordPress roles for WordPress 3.0. * * @since 3.0.0 */ function populate_roles_300() { $role =& get_role( 'administrator' ); if ( !empty( $role ) ) { $role->add_cap( 'update_core' ); $role->add_cap( 'list_users' ); $role->add_cap( 'remove_users' ); $role->add_cap( 'add_users' ); $role->add_cap( 'promote_users' ); $role->add_cap( 'edit_theme_options' ); |
wp-admin/includes/screen.php
This is WordPress Administration Screen API. With user of ‘edit_theme_options’ WordPress take decision to show or not its ‘Welcome’ screen:
891 892 893 894 | if ( 'dashboard' === $this->id && current_user_can( 'edit_theme_options' ) ) { if ( isset( $_GET['welcome'] ) ) { $welcome_checked = empty( $_GET['welcome'] ) ? 0 : 1; update_user_meta( get_current_user_id(), 'show_welcome_panel', $welcome_checked ); |
wp-admin/includes/template.php
This is Template WordPress Administration API. As WordPress developers comment – “A Big Mess. Also some neat functions that are nicely written”.
This code fragment shows again that ‘edit_theme_options’ capability is critical for saving widgets, access to the theme customizer and it is important if you wish to choose image from media library:
1722 1723 1724 1725 1726 1727 | $caps_required = array( 'wp330_media_uploader' => array( 'upload_files' ), 'wp330_saving_widgets' => array( 'edit_theme_options', 'switch_themes' ), 'wp340_customize_current_theme_link' => array( 'edit_theme_options' ), 'wp340_choose_image_from_library' => array( 'edit_theme_options' ), ); |
wp-admin/index.php
This is Dashboard Administration Screen. It uses ‘edit_theme_options’ screen only once to remind you at the Help text, that:
83 84 | if ( current_user_can( 'edit_theme_options' ) ) $help .= '<p>' . __('<strong>Welcome</strong> - Shows links for some of the most common tasks when setting up a new site.') . '</p>'; |
wp-admin/menu.php
This file builds Administration Menu. Capability ‘edit_theme_options’ is used actively at fragment which builds the ‘Appearance’ menu. It is responsible for ‘Menus’ and ‘Themes’ menu items. If user has no ‘switch_themes’ capability, then ‘edit_theme_options’ is checked to show or hide ‘Appearance’ menu.
125 126 127 128 129 130 131 132 133 134 135 | if ( current_user_can( 'switch_themes') ) { $menu[60] = array( __('Appearance'), 'switch_themes', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' ); $submenu['themes.php'][5] = array(__('Themes'), 'switch_themes', 'themes.php'); if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) $submenu['themes.php'][10] = array(__('Menus'), 'edit_theme_options', 'nav-menus.php'); } else { $menu[60] = array( __('Appearance'), 'edit_theme_options', 'themes.php', '', 'menu-top menu-icon-appearance', 'menu-appearance', 'div' ); $submenu['themes.php'][5] = array(__('Themes'), 'edit_theme_options', 'themes.php'); if ( current_theme_supports( 'menus' ) || current_theme_supports( 'widgets' ) ) $submenu['themes.php'][10] = array(__('Menus'), 'edit_theme_options', 'nav-menus.php' ); } |
wp-admin/nav-menus.php
This is WordPress Administration for Navigation Menus Interface functions. It checks ‘edit_theme_options’ capability at very begin and stops execution immediately in case user has no such capability:
21 22 23 | // Permissions Check if ( ! current_user_can('edit_theme_options') ) wp_die( __( 'Cheatin’ uh?' ) ); |
wp-admin/themes.php
This is Themes administration panel. It checks ‘edit_theme_options’ capability twice earlier then previous nav-menus.php and similar – stop execution if user has no such capability:
12 13 | if ( !current_user_can('switch_themes') && !current_user_can('edit_theme_options') ) wp_die( __( 'Cheatin’ uh?' ) ); |
Later for user with ‘edit_theme_options’ capability WordPress offers customized help text:
71 72 73 | if ( current_user_can( 'edit_theme_options' ) ) { $help_customize = '<p>' . __('Click on the "Live Preview" link under any theme to preview that theme and change theme options in a separate, full-screen view. Any installed theme can be previewed and customized in this way.') . '</p>'. |
If user has ‘edit_theme_options’ capability WordPress shows him link to the widgets area:
110 111 112 113 | if ( isset( $_GET['previewed'] ) ) { ?> <div id="message2" class="updated"><p><?php printf( __( 'Settings saved and theme activated. <a href="%s">Visit site</a>.' ), home_url( '/' ) ); ?></p></div> <?php } elseif ( isset($wp_registered_sidebars) && count( (array) $wp_registered_sidebars ) && current_user_can('edit_theme_options') ) { ?> <div id="message2" class="updated"><p><?php printf( __('New theme activated. This theme supports widgets, please visit the <a href="%s">widgets settings</a> screen to configure them.'), admin_url( 'widgets.php' ) ); ?></p></div><?php |
User can see current theme preview. He just should have ‘edit_theme_options’ capability for that:
131 132 133 134 135 | <?php if ( current_user_can( 'edit_theme_options' ) ) : ?> <a href="<?php echo wp_customize_url(); ?>" class="load-customize hide-if-no-customize" title="<?php echo esc_attr( $customize_title ); ?>"> <img src="<?php echo esc_url( $screenshot ); ?>" alt="<?php esc_attr_e( 'Current theme preview' ); ?>" /> </a> <?php endif; ?> |
In order to have ability customize theme presentation: header image, background, etc. ‘edit_theme_options’ capability is critical:
181 182 183 184 185 186 187 | if ( $options || current_user_can( 'edit_theme_options' ) ) : ?> <div class="theme-options"> <?php if ( current_user_can( 'edit_theme_options' ) ) : ?> <a id="customize-current-theme-link" href="<?php echo wp_customize_url(); ?>" class="load-customize hide-if-no-customize" title="<?php echo esc_attr( $customize_title ); ?>"><?php _e( 'Customize' ); ?></a> <?php endif; // edit_theme_options |
wp-admin/widgets.php
This is Widgets administration panel. At line #15, very begin of this file, WordPress checks if user has ‘edit_theme_options’ capability and stops execution if he doesn’t.
15 16 | if ( ! current_user_can('edit_theme_options') ) wp_die( __( 'Cheatin’ uh?' )); |
wp-content/themes/twentyeleven/inc/theme-options.php
This is Twenty Eleven Theme Options. As expected ‘Twenty Eleven’ theme uses ‘edit_theme_options’ capability when adds its own menu item for edit ‘Twenty Eleven’ options:
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | /** * Add our theme options page to the admin menu, including some help documentation. * * This function is attached to the admin_menu action hook. * * @since Twenty Eleven 1.0 */ function twentyeleven_theme_options_add_page() { $theme_page = add_theme_page( __( 'Theme Options', 'twentyeleven' ), // Name of page __( 'Theme Options', 'twentyeleven' ), // Label in menu 'edit_theme_options', // Capability required 'theme_options', // Menu slug, used to uniquely identify the page 'twentyeleven_theme_options_render_page' // Function that renders the options page ); |
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 | /** * Implements Twenty Eleven theme options into Theme Customizer * * @param $wp_customize Theme Customizer object * @return void * * @since Twenty Eleven 1.3 */ function twentyeleven_customize_register( $wp_customize ) { $wp_customize->get_setting( 'blogname' )->transport = 'postMessage'; $wp_customize->get_setting( 'blogdescription' )->transport = 'postMessage'; $options = twentyeleven_get_theme_options(); $defaults = twentyeleven_get_default_theme_options(); $wp_customize->add_setting( 'twentyeleven_theme_options[color_scheme]', array( 'default' => $defaults['color_scheme'], 'type' => 'option', 'capability' => 'edit_theme_options', ) ); |
wp-includes/admin-bar.php
This is Admin Bar. This code handles the building and rendering of the press bar. This file uses ‘edit_theme_options’ capability to check if it’s legal to add ‘Appearance’ menu with ‘Customize’, ‘Widgets’, ‘Menus’, ‘Background’, ‘Header’ items for this user.
565 566 567 568 569 570 571 572 573 574 575 576 577 | /** * Add appearance submenu items to the "Site Name" menu. * * @since 3.1.0 */ function wp_admin_bar_appearance_menu( $wp_admin_bar ) { $wp_admin_bar->add_group( array( 'parent' => 'site-name', 'id' => 'appearance' ) ); if ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) ) $wp_admin_bar->add_menu( array( 'parent' => 'appearance', 'id' => 'themes', 'title' => __('Themes'), 'href' => admin_url('themes.php') ) ); if ( ! current_user_can( 'edit_theme_options' ) ) return; |
wp-includes/class-wp-customize-manager.php
This is WP_Customize_Manager class definition used for the themes Customize functionality. It checks ‘edit_theme_options’ capability before start preview and customize theme.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | /** * Start preview and customize theme. * * Check if customize query variable exist. Init filters to filter the current theme. * * @since 3.4.0 */ public function setup_theme() { send_origin_headers(); if ( is_admin() && ! $this->doing_ajax() ) auth_redirect(); elseif ( $this->doing_ajax() && ! is_user_logged_in() ) $this->wp_die( 0 ); show_admin_bar( false ); if ( ! current_user_can( 'edit_theme_options' ) ) $this->wp_die( -1 ); |
wp-includes/class-wp-customize-section.php
This is Customize Section Class. At line #14 it defines key user capability for himself
14 | public $capability = 'edit_theme_options'; |
and checks it further in the code using check_capabilities() method
43 44 45 46 47 48 49 50 51 52 | /** * Check if the theme supports the section and check user capabilities. * * @since 3.4.0 * * @return bool False if theme doesn't support the section or user doesn't have the capability. */ public final function check_capabilities() { if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) ) return false; |
wp-includes/class-wp-customize-setting.php
This is Customize Setting Class. At line #15 it defines key user capability for himself
14 | public $capability = 'edit_theme_options'; |
and checks it further in the code using check_capabilities() method
254 255 256 257 258 259 260 261 262 263 | /** * Check if the theme supports the setting and check user capabilities. * * @since 3.4.0 * * @return bool False if theme doesn't support the setting or user can't change setting, otherwise true. */ public final function check_capabilities() { if ( $this->capability && ! call_user_func_array( 'current_user_can', (array) $this->capability ) ) return false; |
wp-includes/functions.php
This is Main WordPress API file. It adds ‘Widgets’ menu with check of ‘edit_theme_options’ capability
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 | /** * Append the Widgets menu to the themes main menu. * * @since 2.2.0 * @uses $submenu The administration submenu list. */ function wp_widgets_add_menu() { global $submenu; $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' ); ksort( $submenu['themes.php'], SORT_NUMERIC ); } |
Tags: capability, user capability, WordPress