Add an admin page, but don’t show it on the admin menu

The question:

I have a custom plugin ‘Charts’ that has it’s own menu. In that menu are links to the 3 pages for the plugin – ‘Charts’, ‘Add Chart’ and ‘Edit Chart’. However, I don’t want to display the link to ‘Edit Chart’.

Here is how I add the page in question –

$this->pagehook = add_submenu_page('charts', __('Edit Chart'), __('Edit Chart'), 'edit_charts', 'edit-chart', array(&$this, 'on_show_page'));

I’ve scoured the internet, and cannot find a way to do this (that works). It’s possible to remove whole top level menus (not what I need), and you can remove individual entries from the $submenu global (but doing that also removes the registered capability), so no one can access the page –

global $submenu;
if(!empty($submenu['charts'])) : foreach($submenu['charts'] as $key => $page) :
        if($page[0] === 'Edit Chart') :

            /** Removes all permissions to access the page */
            //unset($submenu['charts'][$key]);              
            /** Removes the title, but the menu entry still exists, so it looks odd */
            $submenu['charts'][$key][0] = '';

        endif;
    endforeach;
endif;

I’ve looked in to hiding it via CSS, but can’t see a way to do that through the HTML that WordPress generates –

<li><a href="admin.php?page=edit-chart" rel="nofollow noreferrer noopener" tabindex="1">Edit Chart</a></li>

I’ve also considered jQuery, but that has similar limitations to the CSS route, plus I refust to believe that I am the only one that has ever wished to do this – there must be a way, I just can’t find it!

Any hints and tips appriciated.

Thanks.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Use a submenu page as parent slug. The admin menu has just two levels, so the imaginary third level will be hidden.

Sample code, tested:

add_action( 'admin_menu', 'wpse_73622_register_hidden_page' );

function wpse_73622_register_hidden_page()
{
    add_submenu_page(
        'options-writing.php',
        'Hidden!',
        'Hidden!',
        'exists',
        'wpse_73622',
        'wpse_73622_render_hidden_page'
    );
    # /wp-admin/admin.php?page=wpse_73622
}

function wpse_73622_render_hidden_page()
{
    echo '<p>hello world</p>';
}

Method 2

From the docs on add_submenu_page(), you see that you can hide your submenu link from a top level menu item to which it belongs be setting the slug (1st argument) to null:

add_action( 'admin_menu', 'register_my_custom_submenu_page' );

function register_my_custom_submenu_page() {
    add_submenu_page( 
        null,
        'My Custom Submenu Page',
        'My Custom Submenu Page',
        'manage_options',
        'my-custom-submenu-page',
        'my_custom_submenu_page_callback',
    );
}

To highlight the desired menu item (e.g. ‘all charts’ when accessing the hidden ‘edit chart’ page), you can do the following:

add_filter( 'submenu_file', function($submenu_file){
    $screen = get_current_screen();
    if($screen->id === 'id-of-page-to-hide'){
        $submenu_file = 'id-of-page-to-higlight';
    }
    return $submenu_file;
});

Method 3

You could use CSS, and you will be able to access it through the URL in the href tag:

#adminmenu a[href="admin.php?page=edit-chart"] { 
    display: none;
}

There are no extra paddings or spacings for the parent LI element, so you don’t need to hide it. You will also still be able to access the submenu.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment