Add Dropdown Pages Links to WordPress Admin Bar

On sites with many pages, opening one to edit means going to Pages, searching and clicking. This snippet adds a Pages dropdown to the WordPress admin bar with an edit link for each page, on the front end and in wp-admin, so any page is two clicks away.

The snippet

<?php
/**
 * Add a "Pages" dropdown to the WordPress admin bar with an edit link for each page.
 * Shown only to users who can edit pages.
 */

// ===== Config =====
function dpc_admin_bar_pages_limit(): int {
	return 100; // How many pages to list.
}
// ===== End of config =====

add_action( 'admin_bar_menu', 'dpc_admin_bar_pages', 999 );

function dpc_admin_bar_pages( WP_Admin_Bar $wp_admin_bar ): void {
	if ( ! current_user_can( 'edit_pages' ) ) {
		return;
	}

	$wp_admin_bar->add_node(
		array(
			'id'    => 'dpc-pages',
			'title' => esc_html__( 'Pages', 'dpc' ),
			'href'  => admin_url( 'edit.php?post_type=page' ),
		)
	);

	$pages = get_posts(
		array(
			'post_type'              => 'page',
			'post_status'            => array( 'publish', 'future', 'draft', 'pending', 'private' ),
			'posts_per_page'         => dpc_admin_bar_pages_limit(),
			'orderby'                => array(
				'menu_order' => 'ASC',
				'title'      => 'ASC',
			),
			'no_found_rows'          => true,
			'update_post_meta_cache' => false,
			'update_post_term_cache' => false,
		)
	);

	foreach ( $pages as $page ) {
		if ( ! current_user_can( 'edit_post', $page->ID ) ) {
			continue;
		}

		$title = wp_strip_all_tags( get_the_title( $page ) );
		if ( '' === $title ) {
			$title = __( '(no title)', 'dpc' );
		}
		if ( 'publish' !== $page->post_status && 'private' !== $page->post_status ) {
			$title .= ' (' . get_post_status_object( $page->post_status )->label . ')';
		}

		$wp_admin_bar->add_node(
			array(
				'id'     => 'dpc-page-' . $page->ID,
				'parent' => 'dpc-pages',
				'title'  => esc_html( $title ),
				'href'   => get_edit_post_link( $page->ID, 'raw' ),
			)
		);
	}
}

Add it with Scripts Organizer

In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor, edit the config and publish. Leave Action/Hook empty. The admin bar shows on the front end too, so Admin only is not enough.

The same code also works unchanged in a small plugin or an mu-plugin.

How it works

  • admin_bar_menu passes the WP_Admin_Bar object; add_node() adds the Pages item, linked to the Pages list, and one child item per page. Priority 999 puts it after the core items.
  • The menu only appears for users with the edit_pages capability (editors and administrators by default), and each page is checked with current_user_can( 'edit_post', $id ).
  • Drafts, pending, scheduled and private pages are listed too, with their status after the title, sorted by page order and then title.
  • get_edit_post_link() builds the edit URL, so it still works when WordPress lives in a subdirectory.
  • The admin bar prints node titles as HTML. The snippet strips tags and escapes the title, so a page title can’t inject markup into every admin screen.

The older version had no capability check, so every logged-in user who sees the admin bar, subscribers included, got a list of all pages with edit links. It also printed titles unescaped, linked the parent item to Oxygen templates and loaded every page on every request.

Customise it

  • More or fewer pages: change the number in dpc_admin_bar_pages_limit().
  • Another post type: change 'page' in get_posts() and the post_type in the parent link, and use a capability that fits, such as edit_posts.
  • Only on the front end: add if ( is_admin() ) { return; } at the top of the function.
  • For a single extra link instead of a list, see Add a Custom Link to the WordPress Admin Bar.

Gotchas

  • With hundreds of pages a dropdown gets too long to use. Keep the limit low and use the Pages search for the rest.
  • Child pages are listed flat, not indented under their parent.

In the Scripts Organizer library Import it with one click from Scripts Organizer.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You’ll also get DPlugins product updates. No spam, and you can unsubscribe anytime.

// newsletter

Three tested WordPress snippets a week

Blocks, security, performance, Tailwind, PHP and React. Copy, paste, ship. You'll also get DPlugins product updates. No spam, and you can unsubscribe anytime.