Icons paneleasy_svg_panel_menu_tabs

easy_svg_panel_menu_tabs

Filters which Icons panel tabs get their own entry under the Icons admin menu, and which capability a user needs to see each of those tabs.

Filter · Easy SVG · Status: Stable

easy_svg_panel_menu_tabs decides two things for the Icons panel: which tabs appear as their own entry under the Icons menu in wp-admin, and which capability a user needs to see each of them. Add your tab here and it gets a menu link that opens the panel on that tab. Give it a lower capability and, for example, editors can open the panel for your tab without seeing the rest.

Usage

apply_filters( 'easy_svg_panel_menu_tabs', array $tabs );
add_filter( 'easy_svg_panel_menu_tabs', 'myaddon_menu_tabs' );

When to use it

  • Your add-on registers a panel tab with window.EasySvgPanel.registerTab() and it should have its own link in the Icons menu.
  • A tab should be reachable by users without manage_options, for example everyone who may upload files.
  • You want to make a free tab stricter in the interface, for example show Settings only to users with manage_network_options.

When not to use it:

  • To put a tab into the panel itself. A menu entry alone draws nothing: the tab has to be registered in JavaScript with the same id.
  • To grant access to Easy SVG's own data. The free REST routes always require manage_options, whatever you declare here.
  • To hide a free tab for everyone. Removing settings or library from the array removes only the menu entry; the panel still draws the tab for administrators (see Pitfalls).

Parameters

body
$tabsarray
Required

Tab id as key, and as value either a plain label string or an array with the keys label and capability.

  • Key: the tab id. It must be identical to the id you pass to registerTab(). Use lowercase letters, digits, _ and - only.
  • Plain string value: the label shown in the menu. The tab then requires manage_options, which is what every tab required before capabilities per tab existed.
  • Array value: label (string, falls back to the tab id when missing) and capability (string, falls back to manage_options when missing). Any primitive capability works, including custom ones your add-on grants.

The array form needs panel contract level 2 or later (EASY_SVG_PANEL_API).

Return value

returnarray

The same shape you received. The result is cast with (array), so always return the array, changed or not.

Default

array(
	'settings' => __( 'Settings', 'easy-svg' ),
	'library'  => __( 'Icon library', 'easy-svg' ),
)

Both are plain labels, so both require manage_options. The order of the array is the order of the submenu entries, after the Icons entry itself.

Examples

A menu entry for your tab

The simplest form: a plain label, visible to administrators only.

add_filter( 'easy_svg_panel_menu_tabs', 'myaddon_menu_tabs' );

function myaddon_menu_tabs( $tabs ) {
	$tabs['myaddon-report'] = __( 'SVG report', 'myaddon' );
	return $tabs;
}

A tab editors may open

With the array form, the tab asks for upload_files. An editor or author now gets the Icons menu, and the panel shows them this one tab. Whatever the tab calls on the server checks the same capability.

add_filter( 'easy_svg_panel_menu_tabs', 'myaddon_menu_tabs' );

function myaddon_menu_tabs( $tabs ) {
	$tabs = (array) $tabs;

	$tabs['myaddon-report'] = array(
		'label'      => __( 'SVG report', 'myaddon' ),
		'capability' => 'upload_files',
	);

	return $tabs;
}

add_action( 'rest_api_init', 'myaddon_routes' );

function myaddon_routes() {
	register_rest_route(
		'myaddon/v1',
		'/report',
		array(
			'methods'             => 'GET',
			'callback'            => 'myaddon_report',
			'permission_callback' => function () {
				return current_user_can( 'upload_files' );
			},
		)
	);
}

Defensive: plain label on older panels

On contract level 1 the array form did not exist. Fall back to a plain label there, which means administrators only.

add_filter( 'easy_svg_panel_menu_tabs', 'myaddon_menu_tabs' );

function myaddon_menu_tabs( $tabs ) {
	$tabs  = (array) $tabs;
	$label = __( 'SVG report', 'myaddon' );

	if ( defined( 'EASY_SVG_PANEL_API' ) && 2 <= (int) EASY_SVG_PANEL_API ) {
		$tabs['myaddon-report'] = array(
			'label'      => $label,
			'capability' => 'upload_files',
		);
	} else {
		$tabs['myaddon-report'] = $label;
	}

	return $tabs;
}

Place your entry first, or make Settings stricter

The array order is the menu order, so you can insert where you like. You can also raise the capability of a free tab: the menu and the panel's tab list both follow it. The free REST routes behind the tab still check manage_options, so this changes what people see, not what they could call.

add_filter( 'easy_svg_panel_menu_tabs', 'myaddon_menu_tabs', 20 );

function myaddon_menu_tabs( $tabs ) {
	$tabs = (array) $tabs;

	// On a multisite network: Settings only for super admins.
	if ( is_multisite() && isset( $tabs['settings'] ) ) {
		$tabs['settings'] = array(
			'label'      => __( 'Settings', 'easy-svg' ),
			'capability' => 'manage_network_options',
		);
	}

	// Our entry before all others.
	return array( 'myaddon-report' => __( 'SVG report', 'myaddon' ) ) + $tabs;
}

How it works

The filter is applied in one place, the function easy_svg_panel_menu_tabs() in includes/panel.php. Several parts of the panel call that function, so your callback runs more than once per request:

  • easy_svg_panel_tabs_for_user() turns every entry into label plus capability (a plain string becomes manage_options) and keeps only the entries for which current_user_can() is true. It is used by the menu, by the menu highlighting and by the page render.
  • easy_svg_panel_menu() runs on admin_menu at priority 9, on every admin page. When the user may see no tab, it registers nothing. Otherwise it adds the top-level Icons page with the capability of the first visible tab, a self entry, and one submenu entry per visible tab with the slug easy-svg-icons&tab=<id>.
  • The submenu_file filter marks the entry of the open tab as current. It runs the tab query value through sanitize_key() and only matches ids that survive that unchanged.
  • easy_svg_panel_tab_capabilities() and easy_svg_panel_user_caps() feed tabCaps (tab id to capability, for every entry) and caps (capability to true or false for this user, plus manage_options) into window.EasySvgPanelData.
  • In the browser the panel shows a tab only when caps[ tabCaps[ id ] ] is true. A tab id that is not in your filter result is looked up as manage_options.

Pitfalls

  • A menu entry is not a tab. If no tab with that id is drawn in the panel, the link opens the panel on its first tab instead.
  • Tabs from third party add-ons are drawn only while Easy SVG Pro is active and licensed. That is how src/panel/App.jsx builds the tab list today. Without that licence your entry opens the first tab, and a user who holds only your custom capability gets an empty panel. Add the entry only when your tab will be drawn (the tutorial shows how).
  • The key must match the JavaScript id exactly. The capability lookup in the browser uses the tab id. Keep ids to lowercase letters, digits, _ and -, otherwise the menu highlighting (which uses sanitize_key()) never marks your entry.
  • Do not reuse built-in ids: settings, library, sets, audit, configurator, licence and upsell belong to Easy SVG and Easy SVG Pro.
  • Removing a free entry does not hide the tab. Without its entry, settings is simply looked up as manage_options in the panel, so administrators still see it. To hide it from someone, raise its capability instead.
  • Lowering a free tab's capability does not help. If you give library the capability edit_posts, editors see the tab, but every request it makes to easy-svg/v1 answers 403, because those routes check manage_options.
  • Always return the array. The value is cast with (array): returning a string turns it into one entry with the id 0.
  • Plain text labels only. WordPress prints submenu titles without escaping, so pass a translated string, never user input or markup.
  • Use primitive capabilities. current_user_can() is called without an object, so meta capabilities such as edit_post do not work here.
  • Keep the callback cheap. It runs on every admin page while the menu is built, and again on the Icons screen. Avoid database queries and remote calls in it.

The capability you declare here controls what the menu and the panel show. It is not an access check for data. Every REST route, AJAX action or form your tab uses must call current_user_can() itself, and should verify the wp_rest nonce the panel sends. A user can always call your endpoint directly, without the panel.