Skip to content
You are reading the docs for ShopClass 7.1.0.dev1, still in development. Read the stable docs.

Administrator menus

Plugins and themes usually need somewhere in the admin panel for their own screens. The menu helpers add sections and entries to the administration menu.

osc_add_admin_menu_page(
$menu_title,
$url,
$menu_id,
$capability = 'administrator',
$icon_url = null,
$position = null
);
osc_add_admin_submenu_page(
$menu_id,
$submenu_title,
$url,
$submenu_id,
$capability = 'administrator',
$group = null,
$match = array()
);

$group names a heading inside the section, such as content or its full id settings_group_content. Settings has these headings: general, content, email, security and system. The entry goes at the end of that group. $match lists other admin URLs that should light this entry, for the tabs of one screen. A declared settings page takes the same placement with 'group' => 'content' and can draw tabs with 'tabs'.

A section keeps its own settings: Listings, Users, Media and Billing each end with a Settings entry, and those screens draw no group tabs. Pages for selling (shipping, tax, offers, digital goods) go into Billing with 'menu' => 'billing' and no group; they sit before Billing’s own Settings entry. With billing switched off there is no Billing section, and such a page goes to the “Other” group of Settings.

The Settings sidebar lists the groups, not the entries. Each Settings screen draws a tab row of its group’s entries, so a plugin entry placed by $group appears as a tab. An entry added to Settings with no group, or an unknown one, goes to an “Other” group. The “Find a setting” box in the top bar searches every entry, and the sections and fields of every declared settings page. To keep a second tab row off a screen, draw the page’s form inside it with osc_admin_settings_form($page, array('titles' => false)) and set 'return_url' on the page so a save comes back to that screen.

A page in a group appears as a tab of that group on every screen of the group, with no further code. Group names are general, content, email, security and system. A page for the shop belongs in Billing instead: 'menu' => 'billing'.

osc_register_settings_page('reports', array(
'title' => __('Reports', 'reports'),
'menu' => 'settings',
'group' => 'content',
));
osc_add_admin_submenu_page(
'settings', __('Reports', 'reports'), $listUrl, 'reports-list',
'administrator', 'content', array($settingsUrl) // $match: other URLs that light this entry
);
osc_remove_admin_menu_page($menu_id);
osc_remove_admin_submenu_page($menu_id, $submenu_id);
osc_remove_admin_menu(); // clears the lot

Removing core entries is a blunt instrument: another plugin may be linking to what you just deleted. Use capabilities to hide a menu instead.

Most plugins belong under a section that already exists, not one of their own. There is a helper for each core section:

osc_admin_menu_items($submenu_title, $url, $submenu_id, $capability = null, $icon_url = null);
osc_admin_menu_categories(…);
osc_admin_menu_pages(…);
osc_admin_menu_appearance(…);
osc_admin_menu_plugins(…);
osc_admin_menu_settings(…);
osc_admin_menu_tools(…);
osc_admin_menu_users(…);
osc_admin_menu_stats(…);

They cover Listings, Categories, Pages, Appearance, Plugins, Settings, Tools, Users and Statistics.

function myplugin_admin_menu()
{
osc_add_admin_menu_page(
__('My plugin', 'myplugin'),
osc_admin_render_plugin_url('myplugin/admin/settings.php'),
'myplugin',
'administrator'
);
osc_add_admin_submenu_page(
'myplugin',
__('Settings', 'myplugin'),
osc_admin_render_plugin_url('myplugin/admin/settings.php'),
'myplugin_settings',
'administrator'
);
}
osc_add_hook('admin_menu_init', 'myplugin_admin_menu');

Use a unique $menu_id. Prefix it with your plugin folder: two plugins claiming the same id overwrite each other’s menus.

Core draws the page header before your screen’s file runs, so the file cannot add to it. Declare it when the plugin loads instead, for a screen on an admin route:

osc_add_hook('init_admin', function () {
osc_admin_plugin_page('myplugin-records', array(
'title' => __('Records', 'myplugin'),
'help' => __('What this screen is for, in a sentence or two.', 'myplugin'),
'actions' => array(
array('icon' => 'bi-plus-circle-fill', 'url' => osc_route_admin_url('myplugin-records-edit'), 'title' => __('Add', 'myplugin')),
),
));
});

title is the browser title. help puts the ? beside the heading, as core screens have; it may be a callable that prints the help. actions are the icon buttons beside it.

Group a plugin’s entries under Plugins with a divider, as core groups its own:

osc_add_admin_submenu_divider('plugins', __('My plugin', 'myplugin'), 'myplugin', 'administrator');