Guide

SlotFills

SlotFills let a module or a separate plugin render React content inside Mantle's admin interface without modifying Mantle. Each slot is created with createSlotFill() from @wordpress/components; Mantle renders the Slot, and your code supplies a Fill.

Available slots

Reference

Registered slots

Created in src/slots/. The name column is the string passed to createSlotFill().
6 fields
Mantle.Panels string
The main content area for a module’s own tab. Exported as MantlePanels and takes a tabId prop so the fill renders only on the matching tab.
Mantle.DashboardWidgets string
Adds a widget to the Mantle dashboard. Exported as MantleDashboardWidgets.
Mantle.SettingsTabs string
Adds a section inside the Settings view. Exported as MantleSettingsTabs.
Mantle.AdvancedTab string
An area reserved for advanced settings. Exported as MantleAdvancedTab.
MantleSidebarBottom string
The bottom of the admin sidebar, intended for help or promotional content. Exported as MantleSidebarBottom. Note this slot name has no dot separator.
Mantle.AdminGlobal string
A global area rendered regardless of the active tab. Not re-exported from src/slots/index.js, so import it from its own module.

Rendering into a slot

The bundled modules pair a mantle.navigation_tabs filter, which creates the tab, with registerPlugin() and a MantlePanels fill, which supplies its content.

jsx src/modules/Reports/register.js
import { addFilter } from '@wordpress/hooks';import { registerPlugin } from '@wordpress/plugins';import { __ } from '@wordpress/i18n';import Reports from './index';import MenuIcon from './MenuIcon';import { MantlePanels } from '@slots';const slug = 'reports';const title = __( 'Reports', 'mantle' );const capability = 'mantle_view_reports';addFilter( 'mantle.navigation_tabs', `mantle/${ slug }`, ( tabs ) => {	const newTab = {		id: slug,		path: `/${ slug }`,		title,		icon: MenuIcon,		order: 60,		component: Reports,		requiredCapability: capability,	};	return [ ...tabs, newTab ];} );registerPlugin( `mantle-${ slug }`, {	render: () => (		<MantlePanels tabId={ slug }>			<Reports />		</MantlePanels>	),} );
The same shape used by src/modules/Security/register.js and its siblings.

Adding a Settings subtab

Mantle.SettingsTabs pairs with the mantle.settings_tabs filter. The fill takes a settingsTabId matching the tab's name, plus an area prop, and its registerPlugin() call must declare scope: 'mantle-settings-tabs'.

jsx src/modules/Reports/settings.js
import { addFilter } from '@wordpress/hooks';import { registerPlugin } from '@wordpress/plugins';import { __ } from '@wordpress/i18n';import ReportsSettings from './ReportsSettings';import { MantleSettingsTabs } from '@slots';addFilter( 'mantle.settings_tabs', 'mantle/reports/register', ( tabs ) => [	...tabs,	{		name: 'reports',		title: __( 'Reports', 'mantle' ),		priority: 50,		className: 'mantle-settings-tab-reports',	},] );registerPlugin( 'mantle-settings-reports', {	scope: 'mantle-settings-tabs',	render: () => (		<MantleSettingsTabs settingsTabId="reports" area="content">			<ReportsSettings />		</MantleSettingsTabs>	),} );
Modelled on src/modules/Modules/register.js, which registers the built-in Modules subtab.

Adding a dashboard widget

jsx src/modules/Reports/widget.js
import { registerPlugin } from '@wordpress/plugins';import { __ } from '@wordpress/i18n';import { MantleDashboardWidgets } from '@slots';const ReportsWidget = () => (	<div>		<h3>{ __( 'Reports', 'mantle' ) }</h3>		<p>{ __( 'Nothing to report yet.', 'mantle' ) }</p>	</div>);registerPlugin( 'mantle-reports-widget', {	render: () => (		<MantleDashboardWidgets>			<ReportsWidget />		</MantleDashboardWidgets>	),} );
Dashboard widgets do not need a tabId.

Where slots live

src/ File tree
  • slots/
    • index.js
    • panels.js
    • dashboard-widgets.js
    • settings-tabs.js
    • advanced-tab.js
    • sidebar-bottom.js
    • global.js
  • modules/
    • ClientInfo/
      • register.js
    • Security/
      • register.js
    • Optimizations/
      • register.js
  • constants/
    • routes.js
  • components/
    • ViewWrapper.js
index.js re-exports every slot except global.js.

Building against Mantle from another plugin

Mantle's slots are registered on the Mantle JavaScript surface at runtime, so an external plugin must enqueue its script after Mantle's admin bundle and declare it as a dependency. Because the slot components come from Mantle's own bundle rather than a published package, external plugins normally re-create the SlotFill by name:

javascript my-plugin/src/admin.js
import { createSlotFill } from '@wordpress/components';import { registerPlugin } from '@wordpress/plugins';// Recreate the SlotFill pair by name. createSlotFill() returns the same// registered slot when the name matches Mantle's.const { Fill: PanelsFill } = createSlotFill( 'Mantle.Panels' );registerPlugin( 'my-plugin-mantle-panel', {	render: () => (		<PanelsFill>			<p>Rendered from a separate plugin.</p>		</PanelsFill>	),} );
Matching the slot name is what connects the fill to Mantle’s slot.

See also

Was this helpful?