Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Ever come across a plugin that is using the manage_options capability for a page that... really doesn't need to be? Well, I've come across just that.

This may be more of a general question about hooking into add_submenu_page, so not just specific to my use-case.

I looked at add_dashboard_page which is simply a wrapper for add_submenu_page:

function add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $menu_slug, $function = '' ) {
    global $submenu;
    global $menu;
    global $_wp_real_parent_file;
    global $_wp_submenu_nopriv;
    global $_registered_pages;
    global $_parent_pages;

    $menu_slug = plugin_basename( $menu_slug );
    $parent_slug = plugin_basename( $parent_slug);

    if ( isset( $_wp_real_parent_file[$parent_slug] ) )
        $parent_slug = $_wp_real_parent_file[$parent_slug];

    if ( !current_user_can( $capability ) ) {
        $_wp_submenu_nopriv[$parent_slug][$menu_slug] = true;
        return false;
    }

    // If the parent doesn't already have a submenu, add a link to the parent
    // as the first item in the submenu. If the submenu file is the same as the
    // parent file someone is trying to link back to the parent manually. In
    // this case, don't automatically add a link back to avoid duplication.
    if (!isset( $submenu[$parent_slug] ) && $menu_slug != $parent_slug ) {
        foreach ( (array)$menu as $parent_menu ) {
            if ( $parent_menu[2] == $parent_slug && current_user_can( $parent_menu[1] ) )
                $submenu[$parent_slug][] = $parent_menu;
        }
    }

    $submenu[$parent_slug][] = array ( $menu_title, $capability, $menu_slug, $page_title );

    $hookname = get_plugin_page_hookname( $menu_slug, $parent_slug);
    if (!empty ( $function ) && !empty ( $hookname ))
        add_action( $hookname, $function );

    $_registered_pages[$hookname] = true;
    // backwards-compatibility for plugins using add_management page. See wp-admin/admin.php for redirect from edit.php to tools.php
    if ( 'tools.php' == $parent_slug )
        $_registered_pages[get_plugin_page_hookname( $menu_slug, 'edit.php')] = true;

    // No parent as top level
    $_parent_pages[$menu_slug] = $parent_slug;

    return $hookname;
}

It honestly doesn't look like there's anything I can actually plug into with an existing dashboard page to change the capability. So I'm trying to decide if I'm better off using remove_submenu_page and then attempt to redeclare that same submenu. I know there will be things I need to look out for (if the display function used for the page has anything that is additionally checking for the capability or displaying anything vital to the site). Always helpful to have a second pair of eyes on these so I don't over complicate things. Thanks all!

Update

Thanks to both @toscho and @userabuser here's what I got:

function wpse_71303_change_menu_cap()
{
    global $submenu;
    foreach ($submenu['index.php'] as $dashboard => $key) {
        if ($key[0] == 'Analytics360°') {
            $submenu['index.php'][$dashboard][1] = 'analytics';
        }
    }
}
add_action( 'admin_head', 'wpse_71303_change_menu_cap' );

If I run a print_r($submenu) I do see the new capability - but I still can't access the menu item under the client role I created (with theanalytics_360` capability) (used the Members plugin to create). Possibly firing too late? Definitely a bit odd. Thanks as always!

The code from Update works for anyone that comes across this. It was an unneeded check around add_dashboard_page() giving me the issue.

share|improve this question
    
What's the problem? You're not specifically stating the use-case/scenario/question. You want to remove a submenu page that is using the manage_options capability? Really doesn't need to be under what context? Curious here... –  userabuser Nov 2 '12 at 13:49
    
A plugin I'm using has manage_options declared as a capability for accessing a plugin page (admin) - I'm looking to see if we can hook into add_submenu_page and change that capability, or if it's better to use remove_submenu_page and then just re-add it. –  Zach Nov 2 '12 at 14:02
2  
As per @toscho answer. I was doing something similar the other date, however specifically altering positions of submenu items. If you var_dump($menu) and or $submenu - you can see what array keys hold which properties. Now I am curious though what option performs better? remove_submenu_page then re-add or just directly modify the global var array. The latter sounds like it would be the case but then whats best practice? In any case, his answer is correct. –  userabuser Nov 2 '12 at 14:24
    
Appreciate your thoughts on this - the performance comparison would be interesting. –  Zach Nov 2 '12 at 14:32
1  
I don't believe you have granted proper permissions up the chain. That might be the issue where a certain permission, despite that of what you set, is taking precedence no matter what. –  userabuser Nov 3 '12 at 17:01

1 Answer 1

up vote 3 down vote accepted

Hook into admin_head, the last action before the menu is rendered, and change the global $menu:

add_action( 'admin_head', 'wpse_71303_change_menu_cap' );

/**
 * Change the capability to access an admin menu item.
 *
 * @wp-hook admin_head
 * @return void
 */
function wpse_71303_change_menu_cap()
{
    global $menu;

    foreach ( $menu as $key => $item )
    {
        // Find menu by name
        if ( 'Tools' === $item[0] ) // default cap: 'edit_posts'
        {
            $menu[ $key ][1] = 'new_capability';
        }
    }
}
share|improve this answer
    
Hey @toscho thanks for the response - definitely getting me off on the right foot. I'm actually looking to hook into $submenu which seems to be giving me some trouble (inside of index.php) - better explained here. Have any thoughts? Thanks! –  Zach Nov 2 '12 at 15:10
    
The problem there seems to be they are using index.php as a key without it actually be a string - so I'm having trouble accessing it correctly. –  Zach Nov 2 '12 at 15:19
    
@Zach Yeah that's right, that's not an error per say. So it goes a little like this $submenu['index.php'][0], then $submenu['index.php'][1] etc. That's how you access the properties of the array. See my link for further example too in OP comments. You are on right track. –  userabuser Nov 2 '12 at 18:58
    
@userabuser Updated my question with progress -- we've got to be almost there :) It seems to attach the new capability correctly, but isn't allowing a role that has that capability to then access the page. –  Zach Nov 2 '12 at 19:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.