A Pro add-on registers submenu pages under the NimblyMail parent menu by listening on nimbly_mail_admin_menu (single-site) or nimbly_mail_network_admin_menu (multisite network admin). Both hooks pass the parent slug so the add-on never needs to hard-code it.
Adding a Submenu Page Under NimblyMail
Signature: do_action( 'nimbly_mail_admin_menu', string $parent_slug )
Fires during admin_menu immediately after NimblyMail registers its own submenu pages.
$parent_slug— the NimblyMail parent menu slug (nimbly-mail). Use this value as the first argument toadd_submenu_page()so the page appears under the correct parent.
@since 1.0.0
add_action(
'nimbly_mail_admin_menu',
function ( string $parent_slug ): void {
add_submenu_page(
$parent_slug,
__( 'Smart Routing', 'nimbly-mail-pro' ),
__( 'Smart Routing', 'nimbly-mail-pro' ),
'manage_options',
'nimbly-mail-routing',
'nimbly_mail_pro_render_routing_page'
);
}
);
/**
* Render the Smart Routing admin page.
*
* @since 1.0.0 Added Smart Routing admin page.
*
* @return void
*/
function nimbly_mail_pro_render_routing_page(): void {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have permission to access this page.', 'nimbly-mail-pro' ) );
}
// Output the mount point for your Vue app.
echo '<div id="nimbly-mail-pro-routing"></div>';
}
Adding a Network Admin Submenu Page
Signature: do_action( 'nimbly_mail_network_admin_menu', string $parent_slug )
Fires during network_admin_menu immediately after NimblyMail registers its own network submenu pages.
@since 1.0.0
add_action(
'nimbly_mail_network_admin_menu',
function ( string $parent_slug ): void {
add_submenu_page(
$parent_slug,
__( 'Network Reports', 'nimbly-mail-pro' ),
__( 'Reports', 'nimbly-mail-pro' ),
'manage_network_options',
'nimbly-mail-pro-network-reports',
'nimbly_mail_pro_render_network_reports_page'
);
}
);
/**
* Render the network reports admin page.
*
* @since 1.0.0 Added network reports admin page.
*
* @return void
*/
function nimbly_mail_pro_render_network_reports_page(): void {
if ( ! current_user_can( 'manage_network_options' ) ) {
wp_die( esc_html__( 'You do not have permission to access this page.', 'nimbly-mail-pro' ) );
}
echo '<div id="nimbly-mail-pro-network-reports"></div>';
}
Enqueuing Your Own Assets
Pro does not share NimblyMail’s Vite bundle. Enqueue your own scripts and styles on your own page only.
The recommended approach is to hook admin_enqueue_scripts and gate on the current screen’s id:
add_action(
'admin_enqueue_scripts',
function ( string $hook_suffix ): void {
// Only enqueue on the Smart Routing page.
if ( 'nimbly-mail_page_nimbly-mail-routing' !== $hook_suffix ) {
return;
}
wp_enqueue_script(
'nimbly-mail-pro-routing',
plugins_url( 'build/routing.js', __FILE__ ),
array(),
'1.0.0',
true
);
wp_enqueue_style(
'nimbly-mail-pro-routing',
plugins_url( 'build/routing.css', __FILE__ ),
array(),
'1.0.0'
);
wp_localize_script(
'nimbly-mail-pro-routing',
'nimblyMailProRouting',
array(
'restRoot' => rest_url( 'nimbly-mail-pro/v1/' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
)
);
}
);
The $hook_suffix for a submenu page registered under nimbly-mail with the page slug nimbly-mail-routing will be nimbly-mail_page_nimbly-mail-routing. WordPress constructs this suffix as {parent_slug}_page_{page_slug}.
Alternatively, capture the return value of add_submenu_page() and use load-{$hook_suffix} for a tighter hook:
add_action(
'nimbly_mail_admin_menu',
function ( string $parent_slug ): void {
$hook = add_submenu_page(
$parent_slug,
__( 'Smart Routing', 'nimbly-mail-pro' ),
__( 'Smart Routing', 'nimbly-mail-pro' ),
'manage_options',
'nimbly-mail-routing',
'nimbly_mail_pro_render_routing_page'
);
add_action(
"load-{$hook}",
function (): void {
// Enqueue assets only when this exact page is loading.
add_action( 'admin_enqueue_scripts', 'nimbly_mail_pro_enqueue_routing_assets' );
}
);
}
);
