SponsoredHosinger Special Offer

WP+ WordPress Plugin Development

Build WordPress plugins from scratch: actions and filters, shortcodes, settings pages, custom post types, meta boxes, AJAX, REST endpoints, custom tables, cron and blocks.

Admin Menus and Pages

WordPress Plugin Development Lesson 9 of 27 ~4 min read

Overview

Plugins add screens to the WordPress dashboard with add_menu_page() and add_submenu_page(), hooked to admin_menu, and each page is protected by a capability that decides which users can see it.

A top-level menu with sub-pages

<?php
function gdc_books_admin_menu() {
    add_menu_page(
        esc_html__( 'GDC Books', 'gdc-books' ),        // <title> of the page.
        esc_html__( 'Books Library', 'gdc-books' ),    // Menu label.
        'manage_options',                              // Capability required.
        'gdc-books',                                   // Unique page slug.
        'gdc_books_render_dashboard',                  // Function that prints the page.
        'dashicons-book-alt',                          // Icon.
        26                                             // Position in the menu.
    );

    add_submenu_page(
        'gdc-books',                                   // Parent slug.
        esc_html__( 'Books Settings', 'gdc-books' ),
        esc_html__( 'Settings', 'gdc-books' ),
        'manage_options',
        'gdc-books-settings',
        'gdc_books_render_settings_page'
    );
}
add_action( 'admin_menu', 'gdc_books_admin_menu' );

Rendering the page

<?php
function gdc_books_render_dashboard() {
    // Belt and braces: the menu already checks, but direct URL access should too.
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( esc_html__( 'You do not have permission to view this page.', 'gdc-books' ) );
    }

    $count = wp_count_posts( 'gdc_book' );
    ?>
    <div class="wrap">
        <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>

        <p>
            <?php
            printf(
                /* translators: %s: number of published books */
                esc_html__( 'You have %s published books.', 'gdc-books' ),
                '<strong>' . esc_html( number_format_i18n( $count->publish ) ) . '</strong>'
            );
            ?>
        </p>

        <a class="button button-primary" href="<?php echo esc_url( admin_url( 'post-new.php?post_type=gdc_book' ) ); ?>">
            <?php esc_html_e( 'Add a book', 'gdc-books' ); ?>
        </a>
    </div>
    <?php
}

Wrap every admin page in <div class="wrap"> and use WordPress's own classes — button, button-primary, widefat, form-table, notice — so your page looks native and stays consistent through WordPress design updates.

Choosing the capability

CapabilityWho has it by defaultUse for
manage_optionsAdministratorsPlugin settings
edit_others_postsEditors and aboveContent management tools
edit_postsContributors and aboveTools any writer may use
readEvery logged-in userPersonal dashboards
Tip: Check capabilities, never roles. current_user_can( 'administrator' ) breaks the moment a site uses a custom role, while current_user_can( 'manage_options' ) keeps working.

Adding pages under existing menus

HelperAdds a page under
add_options_page()Settings
add_management_page()Tools
add_theme_page()Appearance
add_submenu_page( 'edit.php?post_type=gdc_book', ... )Your custom post type's menu

Small plugins should prefer these. A plugin with one settings screen does not deserve its own top-level menu item — users find a crowded admin menu exhausting.

Showing admin notices

<?php
function gdc_books_missing_isbn_notice() {
    $screen = get_current_screen();
    if ( ! $screen || 'edit-gdc_book' !== $screen->id ) {
        return; // Only on the Books list screen.
    }
    ?>
    <div class="notice notice-warning is-dismissible">
        <p><?php esc_html_e( 'Some books are missing an ISBN.', 'gdc-books' ); ?></p>
    </div>
    <?php
}
add_action( 'admin_notices', 'gdc_books_missing_isbn_notice' );

Practice

  • Add the Books Library menu with a Settings sub-page.
  • Log in as an Editor and confirm the menu is hidden; then visit its URL directly and see wp_die() stop you.
  • Show a warning notice only on the Books list screen.
Create a free account to save which lessons you've finished. Save my progress