One of the cool things you can do with WordPress is create your own custom sidebars in the editor.

Screenshot of the WordPress block editor with a custom sidebar opened.
See the sidebar off to the side here?

Check out the video below to get a solid overview of the Plugin Sidebar API and a walk through of how it all works, or keep reading if you prefer not to watch videos.

Watch the Video

Check out this video. It is an introduction to the Plugin API Sidebar section of my Advanced Gutenberg Development Course.

Keep reading if you would like to get a summary of the video in text.

The Plugin API

Adding custom sidebars involves using the Plugin API in WordPress, a slot / fill system that we can hook into with JavaScript and React.

We can access the Plugin API via wp.plugins and get access to a function called registerPlugin that will let us register our own plugin.

const { registerPlugin } = wp.plugins;

registerPlugin("namespace-plugin-name", {
  icon: "dashicon", // Or custom SVG icon
  render: CustomComponentToRender
});

This will register our plugin. Now we can look at setting up the Sidebar.

Plugin API Sidebar

Creating a sidebar involves creating our own custom component that will wrap two important components:

  • <PluginSidebarMoreMenuItem>
  • <PluginSidebar>

Both of these components can be found in wp.editPost.

<PluginSidebarMoreMenuItem>

This component will fill the slot in the editor navigation menu where folks can see a list of plugin sidebars available.

Screenshot showing the plugin sidebar menu
Where our component text will appear

Here is an example of what this will look like at the code level.

<PluginSidebarMoreMenuItem target="namespace-plugin-name">
  {__("Plugin Sidebar Demo", "languagenamespace")}
</PluginSidebarMoreMenuItem>

This component has two important parts. The first is the target. I suggest using the name of your plugin for this, however, it does not need to match. What it does need to match is the name attribute in our <PluginSidebar> component.

The other thing this component has is the name we want to appear in the menu. The icon will show up automatically based on the icon we set for our plugin, so we do not have to add an icon to this component, only text.

<PluginSidebar>

This component will fill the slot for the sidebar itself. Whatever we place inside of <PluginSidebar> will display in the sidebar once it is opened.

The sidebar component with a header and panel row

The component itself is pretty easy to setup. Here is what it looks like:

<PluginSidebar
  name="namespace-plugin-name"
  title={__("Plugin Sidebar Demo", "languagenamespace")}
>
  <PanelBody>
    <PanelRow>
      {__("Plugin Sidebar Content", "languagenamespace")}
    </PanelRow>
  </PanelBody>
</PluginSidebar>

The most important part of this to point out is the <PluginSidebar> name prop. This needs to match the target from the <PluginSidebarMoreMenuItem> target attribute.

In this example I make them both the same as the plugin name, which I think is easiest. But really the do not have to be the same as the plugin name. However, all of these have to be unique to your plugin.

I’ll also mention that I like to use a <PanelBody> and <PanelRow> component inside of my sidebars, but this is not necessary. However, the <PluginSidebar> component does not provide any padding by default, so these components will give you a standard padding similar to core sidebars.

All Together – Complete Example

Now let’s take a look at a complete example using registerPlugin(), <PluginSidebarMoreMenuItem> and <PluginSidebar> all together.

const { __ } = wp.i18n;
const { Fragment } = wp.element;
const { registerPlugin } = wp.plugins;
const { PluginSidebar, PluginSidebarMoreMenuItem } = wp.editPost;
const { PanelBody, PanelRow } = wp.components;

const PluginSidebarDemo = () => (
  <Fragment>
    <PluginSidebarMoreMenuItem target="namespace-plugin-name">
      {__("Plugin Sidebar Demo", "namespace-plugin-name")}
    </PluginSidebarMoreMenuItem>
    <PluginSidebar
      name="namespace-plugin-name"
      title={__("Plugin Sidebar Demo", "namespace-plugin-name")}
    >
      <PanelBody>
        <PanelRow>
          {__("Plugin Sidebar Content", "namespace-plugin-name")}
        </PanelRow>
      </PanelBody>
    </PluginSidebar>
  </Fragment>
);

registerPlugin("namespace-plugin-name", {
  icon: "admin-plugins", // The Plugin Dashicon
  render: PluginSidebarDemo
});

Enqueuing the JavaScript (and CSS)

You will need to enqueue your plugin JavaScript using the enqueue_block_editor_assets hook in your PHP.

In my Advanced Gutenberg Development Course I go in depth into how to set all this up using Webpack and best standards.

But basically you just need some code like this:

add_action( "enqueue_block_editor_assets", __NAMESPACE__ . '\plugin_assets' );
/** 
 * Enqueue block frontend JS & CSS 
 */
function plugin_assets() {
  $plugin_js_path = "/assets/js/plugins.editor.js";
  $plugin_css_path = "/assets/css/plugins.editor.css";

  wp_enqueue_script( 
    'your-plugin-js',
    _get_plugin_url() . $plugin_js_path,
    ['wp-plugins', 'wp-edit-post', 'wp-element', 'wp-plugins', 'wp-i18n', 'wp-components'],
    filemtime( _get_plugin_directory() . $plugin_js_path ),
    true	
  );
  
  wp_enqueue_style(
    'your-plugin-css',
    _get_plugin_url() . $plugin_css_path,
    [],
    filemtime( _get_plugin_directory() . $plugin_css_path )
  );

}

This code won’t work if you just copy and paste it into your own site because it has a few helpful functions in action _get_plugin_url() and _get_plugin_directory(). Here is their source code:

function _get_plugin_directory() {
  return __DIR__;
}

function _get_plugin_url() {
  static $plugin_url;
  if ( empty( $plugin_url ) ) {
    $plugin_url = plugins_url( null, __FILE__ );
  }
  return $plugin_url;
}

The important thing about the enqueueing code above is that you need to have a JavaScript and CSS file located at the following paths:

  • /plugin-root/assets/js/plugins.editor.js
  • /plugin-root/assets/css/plugins.editor.css

If your code is being saved somewhere else then you will need to update your paths.

The other important thing about this code is the JS dependencies. You want to make sure that any path libraries you use in your code you also list as dependencies. This is ensures that everything is loaded, but more importantly that your code is loaded after these libraries are loaded on the page. Otherwise things may not work.

Watch the Video

If you want to see me explain all the terms and walk through the code, check out the video below.

Get the Course

This video comes from my course Advanced Gutenberg Development with WordPress, which I highly recommend as it goes into more depth in working with the Sidebar and Plugin API.