Some time ago I wanted to learn how to extend the Gutenberg sidebar with a dropdown using JavaScript. From previous experience I knew the extension would use either JavaScript or PHP hooks. WordPress is usually easy to work with and I optimistically assumed that it would only take a couple hours at the most to look at the documentation and add the simple extension I wanted. Unfortunately I was wrong. I was very wrong. The documentation existed, but the example code was in a baffling new format that I had never seen before mixing JavaScript and HTML together in a way that was obviously incorrect syntactically. Furthermore, there were no plain vanilla JavaScript examples, even though WordPress had to be implementing it in the background. The following code examples are so that you don’t have to endure the same frustrations I went through.
First, I discovered that the WordPress documentation is in a format called JSX. (JSX stands for JavaScript XML). It is a syntax extension to JavaScript by React JS that will compile the embedded HTML into the proper output. But if you’re like me then you don’t want to deal with it because adding an extra step to compile JS code only complicates what should be a quick coding project.
Finally, after months of trawling through other people’s examples when I had spare time I was finally able to put together something that worked. And now I want to show you how I did it.
The Goal
My objective for this project was to extend the Gutenberg “Shortcode” block by adding a “<select>” dropdown with predefined shortcode tags to side menu in the block inspector. I want this dropdown to contain a list of possible shortcodes I could use to easily populate the shortcode block text area. Having all of my shortcodes in a predefined list will avoid typos.
Extend the Gutenberg Sidebar with a Dropdown
The complete JavaScript code for extending the side menu looks like this. We start by declaring “MyCustomControls” as the name of the callback function which extends the block and finish by using wp.hooks.addFilter to run it during the “editor.BlockEdit” hook. This will extend the Gutenberg sidebar with a dropdown using JavaScript. We will break this down step by step.
// Load our JS code whenever Gutenberg is loaded
add_action('enqueue_block_editor_assets', 'LoadGutenbergScript');
function LoadGutenbergScript() {
// Get script
$script = GutenbergToolbarScript();
// Ensure scripts we depend on are loaded
wp_register_script('shortbus_gutenberg_toolbar', '', ['wp-blocks', 'wp-element', 'wp-i18n', 'wp-editor', 'wp-hooks'], '', true);
// Output the script
wp_enqueue_script('shortbus_gutenberg_toolbar');
wp_add_inline_script('shortbus_gutenberg_toolbar', $script);
}
function GutenbergToolbarScript() {
$script = '
// Name a function to augment block control component with extra enhancements
var MyCustomControls = wp.compose.createHigherOrderComponent(
function(BlockEdit) {
return function (props) {
// If this is NOT a shortcode block then return the default Primary Block Element
if (props.name === "core/shortcode") {
// Return our custom elements
return wp.element.createElement(
wp.element.Fragment, // A container component which renders all children without a wrapping element
{},
// REQUIRED - Primary Block Element
wp.element.createElement(BlockEdit, props), // The default block component that is edited in Gutenburg
// Create element for the default Side Menu block inspector controls
wp.element.createElement(
wp.blockEditor.InspectorControls, // Sidebar controls for the block
{},
// Create a panel element to hold our dropdown
wp.element.createElement(
wp.components.PanelBody,
{},
// Sidebar Dropdown
wp.element.createElement(
wp.components.SelectControl,
{
value: "",
label: "Available Shortcodes",
options: [
{
label: "- Insert Shortcode -",
value: "",
},
{
label: "--------",
value: "",
disabled: true,
},
{
label: "Option #1",
value: "[shortcode-example-1]",
},
{
label: "Option #2",
value: "[shortcode-example-2]",
},
],
onChange: function(value, event) {
// Do something with the value
},
},
)
// END Sidebar Dropdown
)
)
);
}
return wp.element.createElement(BlockEdit, props);
};
},
"MyCustomControls" // The modifier name (similar to a plugin text domain namespace)
);
wp.hooks.addFilter(
"editor.BlockEdit", // The hook name that allows us to modify the focused block
"MY_CUSTOM_CONTROL_NAMESPACE", // Our custom namespace (similar to a plugin text domain)
MyCustomControls // Callback function to modify the block
);
';
return ($script);
}After adding this code our dropdown will appear as desired.
Define the Callback Function
For now we will skip reviewing the PHP section of the code and will focus exclusively on the JavaScript found in the GutenbergToolbarScript() function.
The first thing we do is define the callback function. For example, we named it “MyCustomControlCallback” but you can give it whatever name you want. This callback function “wp.compose.createHigherOrderComponent” is used by WordPress to take a Gutenberg Block component and enhance it. The function takes 2 arguments: a mapComponent and a modifierName.
The modifierName is a seed name used to generate a display name for the enhanced block component.
The mapComponent is an example of JavaScript currying which is beyond the scope of this article. The oversimplified definition of currying is that it converts a function that takes multiple arguments into a sequence of nested functions, each taking a single argument. The first function takes the “BlockEdit” parameter (which is the default block component) and the second function takes the “properties” parameter which contains information about the block component. By default we will use the WordPress “wp.element.createElement” function to return the default (and unmodified) block component. All customization must be done before returning the default block component.
// Name a function to augment a block control component with extra enhancements
var MyCustomControlCallback = wp.compose.createHigherOrderComponent(
function(BlockEdit) {
return function (properties) {
// ...
// Return the unedited block component by default
return wp.element.createElement(BlockEdit, properties);
};
},
"MyCustomControls" // The modifier name is a seed name used to generate a display name
);Limit Customization to Specific Blocks
The next step in our code is to limit our block modifications to only the shortcode block. The hook that we use for modifying Gutenberg blocks is called for each and every block on the page and unless we impose a limitation we will be adding a dropdown to all Gutenberg blocks. That behavior might be useful in some circumstances, but not in this case. We use an conditional statement to only modify the block if its “name” property is equal to “core/shortcode”. Here’s a full list of Gutenberg’s core blocks.
// ...
// If this is a shortcode block then modify it
if (properties.name === "core/shortcode") {
// ...
}
// ...Prepare to Return the Custom Block Element
Inside the “if” condition we use “wp.element.createElement” to return the block with our enhancements added to it. This function accepts 3 arguments: type, props, and children. The type refers to the HTML tag or a specific created element. The props argument is for the properties of the type. And the children argument is an optional array of child elements.
We create the first element using a “wp.element.Fragment” element which is a component that acts as a container but renders its child elements without a wrapper. We pass an empty list of properties to this element.
The first child element of this fragment is the default Block element. This is block editor (paragraph, preformatted, shortcode, etc.) that you edit. We are able to pass the “BlockEdit” and “properties” parameters for it.
// ...
// Return our custom elements
return wp.element.createElement(
wp.element.Fragment, // A container component which renders all children without a wrapping element
{},
// REQUIRED - Primary Block Element
wp.element.createElement(BlockEdit, properties), // The default block component that is edited in Gutenburg
// ...
);
// ...Include the Gutenberg Sidebar Inspector Controls
The second child of the fragment element (defined above) is for the sidebar inspector controls. Just as we defined the default block above, this is the default sidebar. We define it as a “wp.blockEditor.InspectorControls” element. This particular element has an empty object for it properties list. However, because we wanted to add our dropdown to the sidebar we will now start adding child elements.
// ...
// Create element for the default Side Menu block inspector controls
wp.element.createElement(
wp.blockEditor.InspectorControls, // Sidebar controls for the block
{},
// ...
)
// ...Define the Container Panel
We are going to nest a couple of elements inside the sidebar control. Next, we will add a panel that will act as a container (in case we wanted to add multiple inputs or dropdowns) and inside of that we will add our dropdown. We define the panel as a type of “wp.components.PanelBody” with an empty set of properties.
// ...
// Create a panel element to hold our dropdown
wp.element.createElement(
wp.components.PanelBody,
{},
// ...
)
// ...Define the Dropdown
With all of this preparation we are finally able to define our dropdown as a child of the panel element! We create the element as a type of “wp.components.SelectControl“. This tells WordPress that it will be a <select> HTML element. Next, we define its list of properties.
- value – We give this an empty value, but could have pre-selected an option here.
- label – The label to show above the dropdown.
- options – The list of <option> elements that go inside the select. Each option can have its own set of attributes.
- label – The text displayed in the option.
- value – The actual value of the option
- disabled – Boolean that determines if the option can be selected or not.
- onChange – This event is triggered when a different option is selected. It has 2 parameters.
- The value of the <select> dropdown.
- The event that triggered the change.
Here is WordPress’s reference for all available Gutenberg components.
// ...
// Sidebar Dropdown
wp.element.createElement(
wp.components.SelectControl,
{
value: "",
label: "Available Shortcodes",
options: [
{
label: "- Insert Shortcode -",
value: "",
},
{
label: "--------",
value: "",
disabled: true,
},
{
label: "Option #1",
value: "[shortcode-example-1]",
},
{
label: "Option #2",
value: "[shortcode-example-2]",
},
],
onChange: function(value, event) {
// Do something with the value
console.log(value);
},
},
)
// END Sidebar Dropdown
// ...Add the JavaScript Hook
The final step to get our code to work is to attach our callback above to the correct hook. We do that using “wp.hooks.addFilter” and attaching it to the “editor.BlockEdit” hook. This must come after the callback function is defined or else you will receive a JavaScript error! The “wp.hooks.addFilter” function accepts up to 4 arguments: hookName, namespace, callback, and priority. The name of the hook we want is “editor.BlockEdit”. The namespace (used similarly to plugin text domains) can be anything you want, but in this case we used “MY_CUSTOM_CONTROL_NAMESPACE”. The callback was defined earlier as our “MyCustomControlCallback” function. And we simply did not use the optional priority argument.
wp.hooks.addFilter(
"editor.BlockEdit", // The hook name that allows us to modify the focused block
"MY_CUSTOM_CONTROL_NAMESPACE", // Our custom namespace (similar to a plugin text domain)
MyCustomControlCallback // Callback function to modify the block
);Conclusion
It took a significant amount of code to extend a Gutenberg block with a single dropdown. But now that we know how to extend the Gutenberg sidebar with a dropdown we can modify our code to work with textboxes, checkboxes, and any other element we want.
Need more help? Check out our knowledge base for more help articles or contact us for help with your website.









