wp-admin-toolbar
Add, remove, or audit WordPress Admin Toolbar nodes with `admin_bar_menu` and `WP_Admin_Bar`, including capability-aware links, parent/child ordering, accessible markup, frontend/admin/network/editor contexts, and WordPress 7.1's persistent toolbar in the Post and Site Editors. U
Install
npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/wordpress/wp-admin-toolbar
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
git clone https://github.com/Lonsdale201/wp-agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
WordPress Admin Toolbar
Build toolbar extensions through the public PHP API. In WordPress 7.1 the bar is also present by default in the Post and Site Editors, except in Distraction Free mode, so every node must tolerate those contexts.
Add a capability-aware node
add_action(
'admin_bar_menu',
static function ( WP_Admin_Bar $bar ): void {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$bar->add_node(
array(
'id' => 'myplugin-status',
'parent' => false,
'title' => esc_html__( 'Service status', 'my-plugin' ),
'href' => admin_url( 'admin.php?page=my-plugin' ),
'meta' => array(
'class' => 'myplugin-toolbar-status',
'title' => __( 'Open service status', 'my-plugin' ),
),
)
);
},
100
);
Use a globally unique, prefixed id. Add parents before children, keep labels
short, and do not place forms, complex application UI, or request-controlled
HTML in title. A CSS class is not a security boundary.
Context and WordPress 7.1
The same callback may run on the frontend, ordinary wp-admin, network admin,
the Post Editor, and the Site Editor. get_current_screen() is admin-only and
can be null; guard it:
$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
if ( $screen && ( 'site-editor' === $screen->id || $screen->is_block_editor() ) ) {
return;
}
Do not assume the Site Editor is a normal full-page reload context. Re-test focus, submenu positioning, styles, and destinations. Prefer normal links to scripts tied to one document lifecycle. If the node is irrelevant in editors, omit it explicitly rather than hiding it with fragile CSS.
WordPress owns the W logo, site icon, site title, and editor back button. Do not replace their semantics. The toolbar may be absent in Distraction Free mode, so never make it the only path to a required feature.
Remove or change nodes
Hook after the node's registration priority, then use get_node(),
add_node() to update, or remove_node() to remove. Never manipulate the
rendered DOM as the primary implementation.
add_action(
'admin_bar_menu',
static function ( WP_Admin_Bar $bar ): void {
if ( ! current_user_can( 'update_core' ) ) {
$bar->remove_node( 'updates' );
}
},
999
);
Removing a link does not revoke access. Enforce the same capability in the destination screen, REST route, Ajax handler, or mutation callback.
Performance and state
admin_bar_menu runs on every request where the toolbar renders. Avoid remote
HTTP calls, unbounded counts, large queries, or rebuilding expensive state.
Use a short-lived cache for informational counters and make stale status clear.
Never execute a mutation merely because a node renders.
For action links, prefer a destination screen with a POST form. If a direct
action URL is justified, use a capability check, wp_nonce_url(), strict action
handling, and a safe redirect. A nonce proves intent, not authorization.
Accessibility and styling
- Visible text must explain the destination; icon-only nodes need an accessible name and must be tested with core toolbar keyboard navigation.
- Do not use
titlealone as the label. - Scope CSS beneath
#wpadminbarand the prefixed node ID/class. - Do not copy core internal selectors or assume a fixed toolbar height.
- Test zoom, RTL, narrow screens, high contrast, keyboard traversal, and both submenu directions.
Test matrix
Test logged out, subscriber, intended role, administrator, frontend, wp-admin, network admin, Post Editor, Site Editor, Distraction Free mode, no site icon, multisite, mobile/narrow viewport, RTL, direct destination access, invalid nonce, and cached-counter failure. Verify that parent and child IDs remain unique when two integrations are active.
Cross-references
wp-block-editor-iframe-compatibilityfor editor document boundaries.wp-plugin-assets-loadingfor context-gated styles and scripts.wp-security-auditfor destination authorization and nonces.
References
WP_Admin_Bar: https://developer.wordpress.org/reference/classes/wp_admin_bar/admin_bar_menu: https://developer.wordpress.org/reference/hooks/admin_bar_menu/- WordPress 7.1 persistent toolbar: https://make.wordpress.org/core/2026/07/13/consistent-navigation-in-wordpress-7-1-with-persistent-toolbar/
Files (wp-agent-skills)
-
agents
-
openai.yaml 230 B
interface: display_name: "WordPress Admin Toolbar" short_description: "Extend the WordPress toolbar across admin/editor contexts." default_prompt: "Use $wp-admin-toolbar to implement or audit WordPress toolbar integration."
-
-
references
-
node-contract.md 1.5 KB
# WP_Admin_Bar node contract ## Public workflow Use `admin_bar_menu` and its `WP_Admin_Bar` argument. Public operations are: - `add_node( $args )` / legacy alias `add_menu()`; - `get_node( $id )`; - `get_nodes()`; - `remove_node( $id )` / legacy alias `remove_menu()`; - `add_group( $args )` for grouped children. Prefer the node methods over legacy aliases. Do not call internal underscored methods or mutate the private node store. ## Node arguments - `id`: required stable identifier; prefix plugin-owned IDs. - `title`: rendered label/markup; keep it minimal and safe. - `parent`: parent node ID or false for a root node. - `href`: optional destination. - `group`: whether the node is a group container. - `meta`: supported presentation data including `html`, `class`, `rel`, `lang`, `dir`, `onclick`, `target`, `title`, `tabindex`, and `menu_title`. Avoid `meta.html`, `onclick`, and rich `title` markup unless a reviewed public contract truly requires them. Normal links are more robust across contexts. ## Lifecycle Core creates the bar, registers default menus, fires `admin_bar_menu`, then renders it. Choose a priority according to the parent/remove target. Use `wp_before_admin_bar_render` only when code cannot express its ordering through `admin_bar_menu`; it relies on the global bar and is harder to test. The `show_admin_bar` filter controls visibility, but plugins should rarely hide the whole toolbar. A user preference and editor modes can also affect presence.
-
-
SKILL.md 5 KB
--- name: wp-admin-toolbar description: >- Add, remove, or audit WordPress Admin Toolbar nodes with `admin_bar_menu` and `WP_Admin_Bar`, including capability-aware links, parent/child ordering, accessible markup, frontend/admin/network/editor contexts, and WordPress 7.1's persistent toolbar in the Post and Site Editors. Use when a plugin adds quick actions, status links, counters, account menus, or must hide/fix a toolbar node in editor screens. license: GPLv2-or-later metadata: wp-skills-author: "Soczó Kristóf" wp-skills-contact: "mailto:lonsdale201@hotmail.com" wp-skills-plugin: "wordpress" wp-skills-plugin-version-tested: "7.1" wp-skills-wp-version-tested: "7.1" wp-skills-php-min: "7.4" wp-skills-last-updated: "2026-08-20" --- # WordPress Admin Toolbar Build toolbar extensions through the public PHP API. In WordPress 7.1 the bar is also present by default in the Post and Site Editors, except in Distraction Free mode, so every node must tolerate those contexts. ## Add a capability-aware node ```php add_action( 'admin_bar_menu', static function ( WP_Admin_Bar $bar ): void { if ( ! current_user_can( 'manage_options' ) ) { return; } $bar->add_node( array( 'id' => 'myplugin-status', 'parent' => false, 'title' => esc_html__( 'Service status', 'my-plugin' ), 'href' => admin_url( 'admin.php?page=my-plugin' ), 'meta' => array( 'class' => 'myplugin-toolbar-status', 'title' => __( 'Open service status', 'my-plugin' ), ), ) ); }, 100 ); ``` Use a globally unique, prefixed `id`. Add parents before children, keep labels short, and do not place forms, complex application UI, or request-controlled HTML in `title`. A CSS class is not a security boundary. ## Context and WordPress 7.1 The same callback may run on the frontend, ordinary wp-admin, network admin, the Post Editor, and the Site Editor. `get_current_screen()` is admin-only and can be `null`; guard it: ```php $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( $screen && ( 'site-editor' === $screen->id || $screen->is_block_editor() ) ) { return; } ``` Do not assume the Site Editor is a normal full-page reload context. Re-test focus, submenu positioning, styles, and destinations. Prefer normal links to scripts tied to one document lifecycle. If the node is irrelevant in editors, omit it explicitly rather than hiding it with fragile CSS. WordPress owns the W logo, site icon, site title, and editor back button. Do not replace their semantics. The toolbar may be absent in Distraction Free mode, so never make it the only path to a required feature. ## Remove or change nodes Hook after the node's registration priority, then use `get_node()`, `add_node()` to update, or `remove_node()` to remove. Never manipulate the rendered DOM as the primary implementation. ```php add_action( 'admin_bar_menu', static function ( WP_Admin_Bar $bar ): void { if ( ! current_user_can( 'update_core' ) ) { $bar->remove_node( 'updates' ); } }, 999 ); ``` Removing a link does not revoke access. Enforce the same capability in the destination screen, REST route, Ajax handler, or mutation callback. ## Performance and state `admin_bar_menu` runs on every request where the toolbar renders. Avoid remote HTTP calls, unbounded counts, large queries, or rebuilding expensive state. Use a short-lived cache for informational counters and make stale status clear. Never execute a mutation merely because a node renders. For action links, prefer a destination screen with a POST form. If a direct action URL is justified, use a capability check, `wp_nonce_url()`, strict action handling, and a safe redirect. A nonce proves intent, not authorization. ## Accessibility and styling - Visible text must explain the destination; icon-only nodes need an accessible name and must be tested with core toolbar keyboard navigation. - Do not use `title` alone as the label. - Scope CSS beneath `#wpadminbar` and the prefixed node ID/class. - Do not copy core internal selectors or assume a fixed toolbar height. - Test zoom, RTL, narrow screens, high contrast, keyboard traversal, and both submenu directions. ## Test matrix Test logged out, subscriber, intended role, administrator, frontend, wp-admin, network admin, Post Editor, Site Editor, Distraction Free mode, no site icon, multisite, mobile/narrow viewport, RTL, direct destination access, invalid nonce, and cached-counter failure. Verify that parent and child IDs remain unique when two integrations are active. ## Cross-references - `wp-block-editor-iframe-compatibility` for editor document boundaries. - `wp-plugin-assets-loading` for context-gated styles and scripts. - `wp-security-audit` for destination authorization and nonces. ## References - `WP_Admin_Bar`: <https://developer.wordpress.org/reference/classes/wp_admin_bar/> - `admin_bar_menu`: <https://developer.wordpress.org/reference/hooks/admin_bar_menu/> - WordPress 7.1 persistent toolbar: <https://make.wordpress.org/core/2026/07/13/consistent-navigation-in-wordpress-7-1-with-persistent-toolbar/>
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.